-1

Having this Map<Integer, List>:

Map<Integer, List<Integer>> forwardMap = Map.of(
        100, List.of(6),
        300, List.of(49, 52),
        500, List.of(293)
);

I would like to 'flatten' the value Lists and swap the key and value in the Map, ending up with this:

Map<Integer, Integer> reverseMap = Map.of(
         6, 100,
        49, 300
        52, 300,
       293, 500
);

My cannot-compile attempt, where I attempt to stream the Set<Map.Entry> and then the nested List:

Map<Integer, Integer> reverseMap = forwardMap.entrySet().stream().map(
        entry -> entry.getValue().stream().collect(Collectors.toMap(Integer::getInteger, entry.getKey()));
);

Perhaps I need to avoid using stream() twice - possibly by using flatMap() somewhere and somehow. I have also tried first swapping swapping the key and value - but still end up not having a reference to the 'outer' key and the 'inner' nested Integers in the Lists, at the same time.

What am I missing or downright misunderstanding?

morsor
  • 1,263
  • 14
  • 29

2 Answers2

2

Here is a similar answer with a few things added.

  • the keys in your result are sorted so I sorted them in ascending order.
  • In your case, there are no duplicate keys in the final result. If that happens the process will throw an exception. There are three options.
    • keep the first duplicate and its associated value encountered which results in loss of data.
    • keep the last duplicate which has the same effect.
    • return values in a list for duplicate keys.
  • in this exercise, I chose the first option via (first, next)->first merge function.
  • I also return the items in a LinkedHashMap to preserve the sorted order.
Map<Integer, Integer> result = forwardMap.entrySet().stream()
        .flatMap(e -> e.getValue().stream()
                .map(v -> Map.entry(v, e.getKey())))
        .sorted(Entry.comparingByKey())
        .collect(Collectors.toMap(Entry::getKey,
                Entry::getValue, (first, next) -> first,
                LinkedHashMap::new));

result.entrySet().forEach(System.out::println);

prints

6=100
49=300
52=300
293=500

Here is how it would work if you had a duplicate value and wanted to keep it. The only differences are in the final collector.

  • groupingBy is used to create a list for each key
  • a LinkedHashMap is specified to preserve the sorted order.
  • and a mapping collector is used to extract the desired value from the entry.
Map<Integer, List<Integer>> forwardMap =
        Map.of(100, List.of(6), 300, List.of(49, 52), 500,
                List.of(293, 52));

Map<Integer, List<Integer>> result2 =
        forwardMap.entrySet().stream()
                .flatMap(e -> e.getValue().stream()
                        .map(v -> Map.entry(v, e.getKey())))
                .sorted(Entry.comparingByKey())
                .collect(Collectors.groupingBy(
                        Map.Entry::getKey, LinkedHashMap::new,
                        Collectors.mapping(
                                Map.Entry::getValue,
                                Collectors.toList())));

result2.entrySet().forEach(System.out::println);

prints

6=[100]
49=[300]
52=[500, 300]
293=[500]
WJS
  • 36,363
  • 4
  • 24
  • 39
1

As part of your goal is to flatten the values, you're correct you'll probably need a flatMap operation somewhere. For example:

Map<Integer, Integer> reverseMap =
    forwardMap.entrySet().stream()
        .flatMap(
            entry -> entry.getValue().stream().map(value -> Map.entry(value, entry.getKey())))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Slaw
  • 37,820
  • 8
  • 53
  • 80