how to use java streams api to transform a hierarchal map to a flat map

lscoughlin Source

So, I have this function which takes a map, where a name is associated with one of a number of different indexes into an array. The index numbers will only ever have one name associated with them, so no duplicates and no nulls so it's safe to flatten the hierarchy using the following function.

public Map<Integer, Object> normalize( Map<Object, List<Integer>> hierarchalMap ) {

    Map<Integer, Object> normalizedMap = new HashMap<>();
    for (Map.Entry<Object, List<Integer>> entry : hierarchalMap.entrySet()) {
        for (Integer integer : entry.getValue()) {
            noramizedMap.put(integer, entry.getKey());
    return normalizedMap;

I'm trying to change this function into using the streams API and I've gotten this far:

Map<Integer, Object> noramizedMap = new HashMap<>();
for (Map.Entry<Object, List<Integer>> entry : vars.entrySet()) {

    entry.getValue().forEach(e -> noramizedMap.put(e, entry.getValue()));


If this were some other functional language i'd do a partial bind or whatever but with java I try and unwrap the outer loop into a stream...collectTo i just get lost.



answered 6 months ago Eugene #1

Assuming my comment is correct, you can do with Streams like this:

            .flatMap(entry -> entry.getValue()
                    .map(i -> new AbstractMap.SimpleEntry<>(entry.getKey(), i)))
            .collect(Collectors.toMap(Entry::getValue, Entry::getKey));

This assumes there are no duplicates and no nulls.

answered 6 months ago DavW #2

I think this should do what you need:

public Map<Integer, Object> normalizeJava8(Map<Object, List<Integer>> hierarchalMap ) {
    return hierarchalMap
                    (map, entry) -> 
                            entry.getValue().forEach(i -> map.put(i, entry.getKey())),

It's often the case when working with Java 8 streams that you have to put more logic into the "collect" part of the operation than in an equivalent construction in another language, due partially to the lack of a convenient tuple type. Intuitively it might make seem more sane to create a list of pairs then collect them into a map, but that ends up being more code and more computationally intensive than putting that logic in the .collect

answered 6 months ago Federico Peralta Schaffner #3

With streams and Java 9:

Map<Integer, Object> normalizedMap = hierarchalMap.entrySet().stream()
    .flatMap(e -> e.getValue().stream().map(i -> Map.entry(i, e.getKey())))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

This is almost identical to this answer, except I'm using the Map.entry() method to create the pairs and am putting the integers as the keys.

Here's a another, less verbose way to do the same without streams:

Map<Integer, Object> normalizedMap = new HashMap<>();
hierarchalMap.forEach((k, v) -> v.forEach(i -> normalizedMap.put(i, k)));

comments powered by Disqus