Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a reverse map when original map contains collection as the value?

Let's say my original Map contains the following:

Map<String, Set<String>> original = Maps.newHashMap();
original.put("Scott", Sets.newHashSet("Apple", "Pear", "Banana");
original.put("Jack", Sets.newHashSet("Banana", "Apple", "Orange");

And I want to create a reversed Map containing the following:

  "Apple":  ["Scott", "Jack"]
  "Pear":   ["Scott"]
  "Banana": ["Scott", "Jack"]
  "Orange": ["Jack"]

I know it can be done in old fashion (pre-Java 8), but how do I achieve the same using Java Stream API?

Map<String, Set<String>> reversed = original.entrySet().stream().map(x -> ????).collect(??)

There's similar question posted here, but that only works for single valued Maps.

like image 268
nanaboo Avatar asked Feb 15 '19 07:02

nanaboo


1 Answers

You can break the Map into key-value pairs (where each key and value is a single String) by using flatMap, and then collect them as you wish:

Map<String,Set<String>> rev =
    original.entrySet ()
            .stream ()
            .flatMap (e -> e.getValue ()
                            .stream ()
                            .map (v -> new SimpleEntry<String,String>(v,e.getKey ())))
            .collect(Collectors.groupingBy (Map.Entry::getKey,
                                            Collectors.mapping (Map.Entry::getValue, 
                                                                Collectors.toSet())));
System.out.println (rev);

Output:

{Apple=[Jack, Scott], Pear=[Scott], Orange=[Jack], Banana=[Jack, Scott]}
like image 50
Eran Avatar answered Sep 19 '22 10:09

Eran