Create and Invert MultiMap w/ Java 8 Streams
Asked Answered
F

2

8

How can I convert a Set<Result> into a Map<Item, Set<String>> or SetMultimap<Item, String> using Java 8 streams or Multimaps, where Result is:

class Result {
    String name;
    Set<Item> items;
}

For example, I start with:

result1:
    name: name1
    items:
        - item1
        - item2
result2:
    name: name2
    items:
        - item2
        - item3

and end with:

item1:
    - name1
item2:
    - name1
    - name2
item3:
    - name2
Father answered 6/4, 2017 at 4:7 Comment(0)
T
6

two important methods in code snippet below are Stream.flatMap & Collectors.mapping:

import java.util.Map.Entry;
import java.util.AbstractMap.SimpleEntry;
import static java.util.stream.Collectors.*;

results.stream()
    //map Stream<Result> to Stream<Entry<Item>,String>
   .flatMap(it -> it.items.stream().map(item -> new SimpleEntry<>(item, it.name)))
   //group Result.name by Item 
   .collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toSet())));
Threshold answered 6/4, 2017 at 5:12 Comment(4)
nice! was just gonna say that .collect(toList()).stream() is unnecessary but you just edited it. thanks!Father
@mathematician yes, I have already removed, you maybe seen the early version code.Threshold
though this errs with Non-static method cannot be referenced from a static context for the Entry::get methods?Father
@mathematician you must make sure flatMap return a Stream<Map.Entry>.Threshold
E
2

Once there is Collectors.flatMapping in jdk-9, it could look a little different. Also your Item instances need to be comparable in some way, or you can specify that in groupBy (let's say by a field 'itemName'):

Map<Item, Set<String>> map = results.stream()
            .collect(Collectors.flatMapping(
                    (Result result) -> result.getItems()
                            .stream()
                            .map((Item item) -> new AbstractMap.SimpleEntry<>(item, result.getName())),
                    Collectors.groupingBy(Entry::getKey, () -> new TreeMap<>(Comparator.comparing(Item::getItemName)),
                            Collectors.mapping(Entry::getValue, Collectors.toSet()))));
Earmuff answered 6/4, 2017 at 7:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.