简体   繁体   中英

Efficient way of mapping keys of first map to values of second map, where value of first maps are keys of second map

Suppose there are 2 maps such that values of 1st map are keys of 2nd map, as show below

Map1 { k1:[v1,v2,v3], k2:[v4,v5], k3:[v6,v7,v8] }
Map2 { v1:[a1,a2], v2:[a3,a4,a5], v3:[a6], v4:[a7,a8], v5:[a9,a10,a11], v6[a1,a3], v7[a1,a9], v8[a2,a4,a5] }  

I want to make a map say Map3 from the above 2 maps such that

Map3 { 
    k1:[a1,a2,a3,a4,a5,a6],
    k2:[a7,a8,a9,a10,a11],
    k3:[a1,a2,a3,a4,a5,a9]
    }

Are there any inbuilt methods in Java8 Collections API which I can use to derive Map3 in an efficient way, rather than iterating over both the maps to get Map3 in the old Java5 way.

Alternative solution is:

Map<String, List<String>> result  = 
    map1.entrySet().stream()
            .collect(HashMap::new, (m, e) -> m.merge(e.getKey(),
                    e.getValue().stream().flatMap(k -> map2.get(k).stream()).collect(toList()),
                    (l1, l2) -> { l1.addAll(l2);return l1; }),
                    Map::putAll);

Here's a solution using streams:

return map1.entrySet().stream().collect(
    Collectors.toMap(
        Map.Entry::getKey,
        e -> e.getValue().stream()
            .map(map2::get)
            .flatMap(List::stream)
            .distinct()
            .collect(Collectors.toList())));

Output:

{k1=[a1, a2, a3, a4, a5, a6],
 k2=[a7, a8, a9, a10, a11],
 k3=[a1, a3, a9, a2, a4, a5]}

You can add .sorted() after .distinct() if you want the k3 list to be in order.

I would approach it like this.

  1. K is the key type of the first map and key type of returned map
  2. V is the key type for second map and value type in first map
  3. R is the returned map's type.

In your example, assuming the types are all String, call it it like this.

    Map<String,Set<String>> map3 = reMap(map1,map2);

        public static <K, V, R> Map<K, Set<R>> reMap(
            Map<K, List<V>> map1, Map<V, List<R>> map2) {

        Map<K, Set<R>> map3 = new HashMap<>();

        for (Map.Entry<K, List<V>> e : map1.entrySet()) {
            for (V map2key : e.getValue()) {
                map3.compute(e.getKey(),
                        (k, v) -> v == null
                                ? new HashSet<>()
                                : v)
                        .addAll(map2.get(map2key));
            }
        }
        return map3;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM