4

I'm trying to do the following modification:

final Map<String, List<Map<String, String>>> scopes = scopeService.fetchAndCacheScopesDetails();
final Map<String, Map<String, String>> scopesResponse = scopes.entrySet().stream().collect
        (Collectors.toMap(Map.Entry::getKey, e -> e.getValue()
                .stream().collect(Collectors.toMap(s -> (String) s.get(SCOPE_NM), s -> (String) s.get(SCOPE_ID))))
        );

But I face "Duplicate key" error, so I'd like to change scopeResponses to Map<String, Map<String, List<String>>>

Could you tell me how to merge values s -> (String) s.get(SCOPE_ID) into a List or Set in this situation?

Eran
  • 387,369
  • 54
  • 702
  • 768
Pasha
  • 1,768
  • 6
  • 22
  • 43

2 Answers2

5

You need to create a Set for the value of the inner Map, and supply a merge function:

final Map<String, Map<String, Set<String>>> scopesResponse = scopes.entrySet().stream().collect
    (Collectors.toMap(Map.Entry::getKey, e -> e.getValue()
            .stream().collect(Collectors.toMap(s -> s.get(SCOPE_NM),
                                               s -> {Set<String> set= new HashSet<>(); set.add(s.get(SCOPE_ID)); return set;},
                                               (s1,s2)->{s1.addAll(s2);return s1;}))));

Or, you can construct the inner Map with groupingBy:

final Map<String, Map<String, Set<String>>> scopesResponse2 = scopes.entrySet().stream().collect
    (Collectors.toMap(Map.Entry::getKey, e -> e.getValue()
            .stream().collect(Collectors.groupingBy(s -> s.get(SCOPE_NM),
                                               Collectors.mapping(s -> s.get(SCOPE_ID),Collectors.toSet())))));
Eran
  • 387,369
  • 54
  • 702
  • 768
0

You can also do it using Guava's ListMultimap (multimap is like a map of lists):

Map<String, ListMultimap<String, String>> scopesResponse = scopes.entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getKey, e -> toMultimap(e)));

where

static ImmutableListMultimap<String, String> toMultimap(
        Map.Entry<String, List<Map<String, String>>> entry) {
    return entry.getValue().stream().collect(ImmutableListMultimap.toImmutableListMultimap(
            s -> (String) s.get(SCOPE_NM),
            s -> (String) s.get(SCOPE_ID)
    ));
}

If the values in the lists turn out to be duplicated, and you don't want that, use SetMultimap instead.

Tomasz Linkowski
  • 4,386
  • 23
  • 38