Recursively Flatten values of nested maps in Java 8
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]
Related videos on Youtube
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, 2022Comments
-
Ian2thedv over 1 year
Given a
Map<String, Object>
, where the values are either aString
or anotherMap<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) ); }
-
jaco0646 almost 8 yearsstackoverflow.com/questions/21646683/recursive-stream suggests using a method reference.
-
-
AlikElzin-kilaka over 2 yearsNot sure how the result is considered flattened. Result:
[value1, value2, value3.1, value3.2, value3.3.1, value3.3.2]
-
Modus Tollens over 2 yearsYes, that's the result given in the answer. The values of the nested map were merged into one stream.