如何基于公共条目值组合多个映射条目

时间:2016-06-06 00:52:15

标签: java google-maps hashmap

我有一个Multimap结构,Map<String, Set<String>>作为输入。如果任何两组条目值具有公共元素,我想对此映射的条目进行分组。输出的格式应为Map<Set<String>, Set<String>>,其中每个键都是输入映射中的一组键。

例如。鉴于此输入:

A -> [1,2]
B -> [3,4]
C -> [5,6]
D -> [1,5]

输出:

[A,C,D] -> [1,2,5,6]
[B] -> [3,4]

此处A&amp; D1作为共同元素,C&amp; D5作为共同元素。因此,ACD合并为一个密钥。

1 个答案:

答案 0 :(得分:0)

有很多方法可以解决这个问题。我喜欢的(假设您使用的是Java 8)是将其实现为Map.Entry流的收集器。这是一个可能的实现:

public class MapCollector {
    private final Map<Set<String>,Set<Integer>> result = new HashMap<>();

    public void accept(Map.Entry<String,Set<Integer>> entry) {
        Set<String> key = new HashSet<>(Arrays.asList(entry.getKey()));
        Set<Integer> value = new HashSet<>(entry.getValue());
        Set<Set<String>> overlapKeys = result.entrySet().stream()
                .filter(e -> e.getValue().stream().anyMatch(value::contains))
                .map(Map.Entry::getKey)
                .collect(Collectors.toSet());
        overlapKeys.stream().forEach(key::addAll);
        overlapKeys.stream().map(result::get).forEach(value::addAll);
        result.keySet().removeAll(overlapKeys);
        result.put(key, value);
    }

    public MapCollector combine(MapCollector other) {
        other.result.forEach(this::accept);
        return this;
    }

    public static Collector<Map.Entry<String, Set<Integer>>, MapCollector, Map<Set<String>,Set<Integer>>> collector() {
        return Collector.of(MapCollector::new, MapCollector::accept, MapCollector::combine, c -> c.result);
    }
}

可以使用如下:

Map<Set<String>,Set<Integer>> result = input.entrySet().stream()
    .collect(MapCollector.collector());

大多数工作都是在accept方法中完成的。它找到所有重叠集并将它们移动到新的映射条目。它支持并行流,如果您的地图很大,它可能很有用。