convert list of map to map using flatMap
Asked Answered
G

3

9

How I can merge List<Map<String,String>> to Map<String,String> using flatMap?

Here's what I've tried:

final Map<String, String> result = response
    .stream()
    .collect(Collectors.toMap(
        s -> (String) s.get("key"),
        s -> (String) s.get("value")));
result
    .entrySet()
    .forEach(e -> System.out.println(e.getKey() + " -> " + e.getValue()));

This does not work.

Grisby answered 26/10, 2017 at 22:13 Comment(2)
Can map keys collide, or are they guaranteed unique? If they can collide, what action do you want—take the first one, concatenate them together, maintain a count, what?Brothers
What are you trying to do ? Concatenate all keys together, same for value ?Remission
H
16

Assuming that there are no conflicting keys in the maps contained in your list, try following:

Map<String, String> maps = list.stream()
    .flatMap(map -> map.entrySet().stream())
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Hypophyge answered 26/10, 2017 at 22:55 Comment(3)
You'll see in my answer: adding a merge function to the toMap call avoids the conflicts issue.Compensatory
@sprinter, by merge function do you mean the Set::stream? It's not needed. If you add duplicate keys in a map the last one overwrites the previous ones.Hypophyge
no that's not how toMap works. From the doc: "If the mapped keys contain duplicates (according to Object.equals(Object)), an IllegalStateException is thrown when the collection operation is performed. If the mapped keys might have duplicates, use toMap(Function, Function, BinaryOperator) instead." The binary operator I used in my solution is Map::putAll which handles the duplicates.Compensatory
C
6

A very simple way would be to just use putAll:

Map<String, String> result = new HashMap<>();
response.forEach(result::putAll);

If you particularly want to do this in a single stream operation then use a reduction:

response.stream().reduce(HashMap<String, String>::new, Map::putAll);

Or if you really want to use flatMap:

response.stream().map(Map::entrySet).flatMap(Set::stream)
    .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, Map::putAll));

Note the merging function in the final alternative.

Compensatory answered 26/10, 2017 at 23:46 Comment(0)
V
4

If you're ok with overriding the keys, you can just merge the Maps into a single map with collect, even without flatMaps:

public static void main(String[] args) throws Exception {
    final List<Map<String, String>> cavia = new ArrayList<Map<String, String>>() {{
        add(new HashMap<String, String>() {{
            put("key1", "value1");
            put("key2", "value2");
            put("key3", "value3");
            put("key4", "value4");
        }});
        add(new HashMap<String, String>() {{
            put("key5", "value5");
            put("key6", "value6");
            put("key7", "value7");
            put("key8", "value8");
        }});
        add(new HashMap<String, String>() {{
            put("key1", "value1!");
            put("key5", "value5!");
        }});
    }};

    cavia
            .stream()
            .collect(HashMap::new, HashMap::putAll, HashMap::putAll)
            .entrySet()
            .forEach(System.out::println);
}

Will output:

key1=value1!
key2=value2
key5=value5!
key6=value6
key3=value3
key4=value4
key7=value7
key8=value8
Verisimilitude answered 26/10, 2017 at 23:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.