Recursively Flatten values of nested maps in Java 8

16,136

You could define a recursive method which flattens one map and use it as a function for Stream#flatMap or use it by calling it directly.

Example:

public class FlatMap {

    public static Stream<Object> flatten(Object o) {
        if (o instanceof Map<?, ?>) {
            return ((Map<?, ?>) o).values().stream().flatMap(FlatMap::flatten);
        }
        return Stream.of(o);
    }

    public static void main(String[] args) {
        Map<String, Object> map0 = new TreeMap<>();
        map0.put("key1", "value1");
        map0.put("key2", "value2");
        Map<String, Object> map1 = new TreeMap<>();
        map0.put("key3", map1);
        map1.put("key3.1", "value3.1");
        map1.put("key3.2", "value3.2");
        Map<String, Object> map2 = new TreeMap<>();
        map1.put("key3.3", map2);
        map2.put("key3.3.1", "value3.3.1");
        map2.put("key3.3.2", "value3.3.2");

        List<Object> collect = map0.values().stream()
                                            .flatMap(FlatMap::flatten)
                                            .collect(Collectors.toList());
        // or
        List<Object> collect2 = flatten(map0).collect(Collectors.toList());
        System.out.println(collect); 
    }
}

For the given nested map, it prints

[value1, value2, value3.1, value3.2, value3.3.1, value3.3.2]

Share:
16,136

Related videos on Youtube

Ian2thedv
Author by

Ian2thedv

My main quest in life is not dying. Side quests includes hiking, surfing and becoming a master chef. Major time wasters are sleeping, reading, gaming and failing to persuade my girlfriend wife to eat my lasagne. I also like coding. COVID update: still doing pretty good on main quest, but miserably failed the "Impress wife with cooking" side quest. I have recently embarked on the "How long can I stay inside without anyone asking questions" side quest, which has been a lot more fun than originally anticipated.

Updated on September 15, 2022

Comments

  • Ian2thedv
    Ian2thedv over 1 year

    Given a Map<String, Object>, where the values are either a String or another Map<String, Object>, how would one, using Java 8, flatten the maps to a single list of values?

    Example:

    Map - "key1" -> "value1"
        - "key2" -> "value2"
        - "key3" -> Map - "key3.1" -> "value3.1"
                        - "key3.2" -> "value3.2"
                        - "key3.3" -> Map - "key3.3.1" -> "value3.3.1"
                                          - "key3.3.2" -> "value3.3.2" 
    

    For the above example, I would like the following list:

    value1
    value2
    value3.1
    value3.2
    value3.3.1
    value3.3.2
    

    I know it can be done like this:

    public static void main(String args[]) throws Exception {
        //Map with nested maps with nested maps with nested maps with nested......
        Map<String, Object> map = getSomeMapWithNestedMaps();
    
        List<Object> values = new ArrayList<>();
        addToList(map, values);
    
        for (Object o:values) {
            System.out.println(o);
        }
    }
    
    static void addToList(Map<String, Object>map, List<Object> list) {
        for (Object o:map.values()) {
            if (o instanceof Map) {
                addToList((Map<String, Object>)o, list);
            } else {
                list.add(o);
            }
        }
    }
    

    How can I do this with a Stream?

    Edit:

    After some playing around I figured it out:

    public static void main(String args[]) throws Exception {
        //Map with nested maps with nested maps with nested maps with nested......
        Map<String, Object> map = getSomeMapWithNestedMaps();
        //Recursively flatten maps and print out all values
        List<Object> list= flatten(map.values().stream()).collect(Collectors.toList());
    }
    
    static Stream<Object> flatten(Stream<Object> stream) {
        return stream.flatMap((o) ->
            (o instanceof Map) ? flatten(((Map<String, Object>)o).values().stream()) : Stream.of(o)
        );
    }
    
  • AlikElzin-kilaka
    AlikElzin-kilaka over 2 years
    Not sure how the result is considered flattened. Result: [value1, value2, value3.1, value3.2, value3.3.1, value3.3.2]
  • Modus Tollens
    Modus Tollens over 2 years
    Yes, that's the result given in the answer. The values of the nested map were merged into one stream.