james
james

Reputation: 13

Map objects by occurrences in list of pairs

I need to map a list of pairs of objects into <ocurrences, list of Objs with those ocurrences>, I've tried using streams directly on the input list of pairs but I'm still kind of new to java and couldn't figure it out, so I was trying to do something like this, but it's probably not close to the best way to do it.

public Map<Integer,ArrayList<Obj>> numBorders(List<Pair<Obj,Obj>> lf) {

    Map<Integer,ArrayList<Obj>> nBorders = new HashMap<>();

    List<Obj> list = new ArrayList<>();

    for(Pair<Obj, Obj> pair : lf) {
        list.add(pair.getKey());
        list.add(pair.getValue());
    }

    nBorders = list.stream().collect(Collectors.groupingBy(...);
    return nBorders;
}

so for example, for lf = {(o1,o2),(o3,o2),(o5,o4),(o4,o1),(o3,o4),(o7,o1),(o5,o8),(o3,o10),(o4,o5),(o3,o7),(o9,o8)} the result should be {(1,{o9,o10}),(2,{o2,o7,o8,}),(3,{o1,o5}),(4,{o3,o4})}.

I'm really confused on how to do this, if someone could help, I'd appreciate it, thanks.

Upvotes: 0

Views: 356

Answers (1)

Nowhere Man
Nowhere Man

Reputation: 19545

This can be done this way:

  1. create a stream from the pairs to concatenate first/second values using Stream::flatMap
  2. count the occurrences - build an intermediate map <Obj, Integer> using Collectors.groupingBy + Collectors.summingInt (to keep integer)
  3. create an inverse map <Integer, List> from the stream of the entries in the intermediate map using Collectors.groupingBy + Collectors.mapping

Optionally, if an order in the resulting map is critical, a LinkedHashMap may be created from the entries of the intermediate frequency map sorted by value.

public Map<Integer,ArrayList<Obj>> numBorders(List<Pair<Obj,Obj>> lf) {

    return lf.stream() // Stream<Pair>
             .flatMap(p -> Stream.of(p.getKey(), p.getValue())) // Stream<Obj>
             .collect(Collectors.groupingBy(
                 obj -> obj,
                 Collectors.summingInt(obj -> 1)
             )) // Map<Obj, Integer>
             .entrySet()
             .stream() // Stream<Map.Entry<Obj, Integer>>
             .sorted(Map.Entry.comparingByValue())
             .collect(Collectors.groupingBy(
                 Map.Entry::getValue, // frequency is key
                 LinkedHashMap::new,
                 Collectors.mapping(Map.Entry::getKey, Collectors.toList())
             )); // Map<Integer, List<Obj>>
}

Upvotes: 3

Related Questions