How to convert List<Map<K,V>> into Map<K,List<V>> In java
Consider the following problem . I want to convert List of maps to the map.
Input
[ {a=1, b=2}, {a=3, d=4, e=5}, {a=5,b=6,e=7} ]
Output
{ a=[1,3,5], b=[2,6], d=[4], e=[5,7] }
I tried the following code.
Code
static <K,V> Map<K,List<V>> getMapFromTheList(List<Map<K,V>> list) { return list.stream().flatMap(map -> map.entrySet().stream()) .collect(Collectors.groupingBy(Map.Entry::getKey,Collectors.mapping(Map.Entry::getValue, Collectors.toList()))); }
Is there any better way of doing this ? More simpler way or more efficient way ?
The alternatives could look like :
static <K,V> Map<K,List<V>> getMapFromTheListOld_1(List<Map<K,V>> list){ Map<K,List<V>> map = new HashMap<>(); for(Map<K,V> m : list){ for(Map.Entry<K,V> e : m.entrySet()){ if( !map.containsKey(e.getKey())){ map.put(e.getKey(), new ArrayList<>()); } map.get(e.getKey()).add(e.getValue()); } } return map; }
You could simplify the inner loop using Map#computeIfAbsent
:
static <K,V> Map<K,List<V>> getMapFromTheListOld_2(List<Map<K,V>> list){ Map<K,List<V>> map = new HashMap<>(); for(Map<K,V> m : list){ for(Map.Entry<K,V> e : m.entrySet()){ map.computeIfAbsent(e.getKey(), k -> new ArrayList<>()).add(e.getValue()); } } return map; }
But IMO both approachs are not easier than your one-liner using streams. You could add some new lines to make it more readable though:
static <K,V> Map<K,List<V>> getMapFromTheList(List<Map<K,V>> list){ return list.stream() .flatMap(map -> map.entrySet().stream()) .collect(Collectors.groupingBy( Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.toList()))); }
Java stream api is the best and efficient way to do that. Its fast when working with collections as the support parallel execution of your collection data using stream. This was the intention of introducing stream api in java 8 of reducing the a lot of looping for evaluating and computing your data. So from my point of you, your code is correct and efficient.