Java 合并两张地图

Java 合并两张地图,java,map,merge,Java,Map,Merge,我有两个映射,它们的键是Strings,值是Set。给定两个Maps,合并它们的最简单方法是什么?如果两个键相同,则值是两个集的并集。您可以假设值从不为空,如果它有用,我们可以使这些MapsSortedMaps.我们所说的是HashMap实例。在这种情况下,lookup是O(1),因此您可以只取一个映射,迭代该映射的条目,查看另一个映射是否包含该键。如果没有,只需添加集合。如果包含键,则取两个集合的并集(通过一个集合到另一个集合的并集) 为了用一些代码来说明,我在IDE中使用了一个集合来实现自动

我有两个映射,它们的键是
String
s,值是
Set
。给定两个
Map
s,合并它们的最简单方法是什么?如果两个键相同,则值是两个集的并集。您可以假设值从不为空,如果它有用,我们可以使这些
Map
s
SortedMap
s.

我们所说的是
HashMap
实例。在这种情况下,lookup是O(1),因此您可以只取一个映射,迭代该映射的条目,查看另一个映射是否包含该键。如果没有,只需添加集合。如果包含键,则取两个集合的并集(通过一个集合到另一个集合的并集)

为了用一些代码来说明,我在IDE中使用了一个集合来实现自动完成

Map<String, Set<Double>> firstMap = new HashMap<String, Set<Double>>(  );
Map<String, Set<Double>> secondMap = new HashMap<String, Set<Double>>(  );
Set<Map.Entry<String, Set<Double>>> entries = firstMap.entrySet();
for ( Map.Entry<String, Set<Double>> entry : entries ) {
  Set<Double> secondMapValue = secondMap.get( entry.getKey() );
  if ( secondMapValue == null ) {
    secondMap.put( entry.getKey(), entry.getValue() );
  }
  else {
    secondMapValue.addAll( entry.getValue() );
  }
}
Map firstMap=newhashmap();
Map secondMap=newhashmap();
Set entries=firstMap.entrySet();
用于(映射条目:条目){
设置secondMapValue=secondMap.get(entry.getKey());
if(secondMapValue==null){
secondMap.put(entry.getKey(),entry.getValue());
}
否则{
secondMapValue.addAll(entry.getValue());
}
}

以下内容应将
map1
合并到
map2
(未测试):

for(条目这个如何(未测试):

Map m1=//输入映射
Map m2=//输入映射
Map ret=//新建空映射
ret.putAll(m1);
for(字符串键:m2.keySet()){
如果(返回集装箱(钥匙)){
ret.get(key).addAll(m2.get(key));
}否则{
返回放置(键,m2获取(键));
}
}
这个解决方案不修改输入映射,而且因为它很短并且只依赖于API方法,所以我觉得它非常可读

请注意,和都是
Map
Set
中的可选方法。因此(为了获得O(1)查找),我建议使用和

请注意,由于
HashSet
HashMap
都不同步,因此如果需要线程安全代码,则需要寻找其他解决方案。

类似于以下内容(未测试):

//假设所有映射都是相同的泛型类型。
公共静态地图合并所有(地图m1、地图m2){
Map merged=新的HashMap();
//将常用条目合并到新映射中。
对于(Map.Entry:m1.entrySet()){
String key=entry.getKey();
Set s1=新的HashSet(entry.getValue());
设置s2=m2.get(键);
如果(s2!=null)s1.addAll(s2);
合并。放置(键,s1);
}
//将m2独有的条目添加到新地图。
对于(字符串键:m2.keys()){
如果(!s1.containsKey(key))合并了.put(key,新HashSet(m2.get(key));
}
返回合并;
}
请注意,此解决方案不会改变其任何一个参数。

Map m1=new HashMap();
Map<Integer,String> m1=new HashMap<Integer,String>();
Map<Integer,String> m2=new HashMap<Integer,String>();
m1.put(1,"one");
m1.put(2,"two");
m2.put(3,"three");
m2.put(2,"two");
Set<Integer> s=m2.keySet();
for(int i:s){
    if(m1.get(i)==null){
        m1.put(i,m2.get(i));
    }
}
System.out.println(m1);
Map m2=新的HashMap(); m1.投入(1,“一”); m1.put(2,“两”); m2.投入(3,“三”); m2.投入(2,“两”); 设置s=m2.keySet(); 用于(int i:s){ 如果(m1.get(i)=null){ m1.put(i,m2.get(i)); } } 系统输出打印项次(m1);
请注意,所有其他答案最终都会增加您可能不希望用于所有用例的原始集合,如果您不希望这样做,只需使用第三个映射作为输出,并为每个键创建一个新集合

public static void merge2Maps(Map<String, Set<Double>> a, Map<String, Set<Double>> b, Map<String, Set<Double>> c){

    for (Map.Entry<String, Set<Double>> entry : a.entrySet()) {
        Set<Double> set = new HashSet<Double>();
        c.put(entry.getKey(), set);
        set.addAll(entry.getValue());
    }

    for (Map.Entry<String, Set<Double>> entry : b.entrySet()) {
        String key = entry.getKey();
        Set<Double> set = c.get(key);

        if (set == null) {
            set = new HashSet<Double>();
            c.put(entry.getKey(), set);
        }

        set.addAll(entry.getValue());
    }
}
publicstaticvoidmerge2map(图a、图b、图c){
对于(Map.Entry:a.entrySet()){
Set=newhashset();
c、 put(entry.getKey(),set);
set.addAll(entry.getValue());
}
对于(Map.Entry:b.entrySet()){
String key=entry.getKey();
Set=c.get(键);
if(set==null){
set=新的HashSet();
c、 put(entry.getKey(),set);
}
set.addAll(entry.getValue());
}
}
您可以非常轻松地使用以下工具完成此操作:

Map<T, Set<U>> merged = Stream.of(first, second)
        .map(Map::entrySet)
        .flatMap(Set::stream)
        .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (a, b) -> {
            HashSet<U> both = new HashSet<>(a);
            both.addAll(b);
            return both;
        }));
如果没有重复的键,
收集器.toMap
的第三个参数是不必要的


还有第四个参数可以让你决定收集到的
地图的类型。

如果你想以不可变的数据结构结束,以防止对合并地图和地图集合实例的操纵,那么你可以采用这种方法。此解决方案使用谷歌的Guava库

public <K,T> Map<K, Set<T>> mergeToImmutable (
    final Map<K, Set<T>> left,
    final Map<K, Set<T>> right)
{
    return Maps.toMap(
        Sets.union(
            checkNotNull(left).keySet(),
            checkNotNull(right).keySet()
        ),
        new Function<K, Set<T>> () {
            @Override
            public Set<T> apply (K input) {
                return ImmutableSet.<T>builder()
                    .addAll(MoreObjects.firstNonNull(left.get(input), Collections.<T>emptySet()))
                    .addAll(MoreObjects.firstNonNull(right.get(input), Collections.<T>emptySet()))
                    .build();
            }
        }
    );
}
publicmap mergeToImmutable(
最后的地图左边,
最终地图(右)
{
返回Maps.toMap(
集合。联合(
checkNotNull(左)。键集(),
checkNotNull(右)。键集()
),
新函数(){
@凌驾
公共集应用(K输入){
返回ImmutableSet.builder()
.addAll(MoreObjects.firstNonNull(left.get(输入),Collections.emptySet())
.addAll(MoreObjects.firstNonNull(right.get(输入),Collections.emptySet())
.build();
}
}
);
}

如果您定义了一种方法来统一非空
设置
s为:

static <T> Set<T> union(Set<T>... sets) {
    return Stream.of(sets)
                 .filter(s -> s != null)
                 .flatMap(Set::stream)
                 .collect(Collectors.toSet());
}
或者更简单:

Map<String, V> merged = new HashMap<>();
for (String k : union(m1.keySet(), m2.keySet())
     merged.put(k, union(m1.get(k), m2.get(k)));
Map merged=newhashmap();
for(字符串k:union(m1.keySet(),m2.keySet())
并置(k,并集(m1.get(k),m2.get(k));
映射合并映射列表(流){
回流
.map(map::entrySet)//将每个映射转换为映射的条目集
.flatMap(Collection::stream)//将每个映射条目转换为流,并将其平坦化为一个流
.collect(toMap)(Map.Entry::getKey,Map.Entry::getValue,
(列表1、列表2)->{
列表1.addAll(列表2);
返回列表1;
}));//将流转换为映射;如果键重复,则执行合并功能(使用新列表中的元素追加现有列表)
}
静态无效合并集(地图map1、地图map2){
映射1.forEach((键1,值1)->{
map2.merge(key1,value1,(key2,value2)->key2.addAll(value1);
});
}

对于
m2
中但不在
m1
中的键呢?你调用
m2.getValue()
,但是
m2
是一个
映射
,因此没有
getValue()
方法。@MichaelMcGowan:哦,对了,也解决了这个问题(天啊,看看当我试图关闭代码时会发生什么)
public <K,T> Map<K, Set<T>> mergeToImmutable (
    final Map<K, Set<T>> left,
    final Map<K, Set<T>> right)
{
    return Maps.toMap(
        Sets.union(
            checkNotNull(left).keySet(),
            checkNotNull(right).keySet()
        ),
        new Function<K, Set<T>> () {
            @Override
            public Set<T> apply (K input) {
                return ImmutableSet.<T>builder()
                    .addAll(MoreObjects.firstNonNull(left.get(input), Collections.<T>emptySet()))
                    .addAll(MoreObjects.firstNonNull(right.get(input), Collections.<T>emptySet()))
                    .build();
            }
        }
    );
}
static <T> Set<T> union(Set<T>... sets) {
    return Stream.of(sets)
                 .filter(s -> s != null)
                 .flatMap(Set::stream)
                 .collect(Collectors.toSet());
}
Map<String, V> merged
    = union(m1.keySet(), m2.keySet())
           .stream()
           .collect(Collectors.toMap(k -> k, k -> union(m1.get(k), m2.get(k)))); 
Map<String, V> merged = new HashMap<>();
for (String k : union(m1.keySet(), m2.keySet())
     merged.put(k, union(m1.get(k), m2.get(k)));
<K, V> Map<K, List<V>> mergeMapOfLists(Stream<Map<K, List<V>>> stream) {
    return stream
            .map(Map::entrySet) // convert each map to set of map's entries
            .flatMap(Collection::stream) // convert each map entry to stream and flat them to one stream
            .collect(toMap(Map.Entry::getKey, Map.Entry::getValue,
                    (list1, list2) -> {
                        list1.addAll(list2);
                        return list1;
                    })); // convert stream to map; if key is duplicated execute merge fuction (append exisitng list with elements from new list)
}
static void mergeSet(Map<String, Set<String>> map1, Map<String, Set<String>> map2) {
    map1.forEach((key1, value1) -> {
        map2.merge(key1, value1, (key2, value2) -> key2).addAll(value1);
    });
}