我有一个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; D
将1
作为共同元素,C
&amp; D
将5
作为共同元素。因此,A
,C
,D
合并为一个密钥。
答案 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
方法中完成的。它找到所有重叠集并将它们移动到新的映射条目。它支持并行流,如果您的地图很大,它可能很有用。