我如何组合两个HashMap对象包含相同的类型?

我有两个HashMap对象,定义如下:

HashMap<String, Integer> map1 = new HashMap<String, Integer>();
HashMap<String, Integer> map2 = new HashMap<String, Integer>();

我还有第三个HashMap对象:

HashMap<String, Integer> map3;

如何将map1map2合并为map3?

335345 次浏览

你可以将Collection.addAll ()用于其他类型,例如ListSet等。对于Map,可以使用putAll

map3 = new HashMap<>();


map3.putAll(map1);
map3.putAll(map2);

如果你的最终映射不需要可变性,有番石榴的 ImmutableMap和它的BuilderputAll方法,与Java的Map接口方法相反,可以被链接。

使用示例:

Map<String, Integer> mergeMyTwoMaps(Map<String, Integer> map1, Map<String, Integer> map2) {
return ImmutableMap.<String, Integer>builder()
.putAll(map1)
.putAll(map2)
.build();
}

当然,这个方法可以更通用,使用可变参数和从参数循环到putAll Maps等,但我想展示一个概念。

而且,ImmutableMap和它的Builder有一些限制(或者可能是特性?):

  • 它们是空敌对的(抛出NullPointerException -如果map中的任何键或值为空)
  • 生成器不接受重复的键(如果添加了重复的键,则抛出IllegalArgumentException)。

如果你知道你没有重复的键,或者你想让map2中的值覆盖map1中的值以获得重复的键,你可以只写

map3 = new HashMap<>(map1);
map3.putAll(map2);

如果你需要更多的控制值的组合方式,你可以使用在Java 8中添加的Map.merge,它使用用户提供的BiFunction来合并重复键的值。merge操作单独的键和值,所以你需要使用循环或Map.forEach。这里我们连接重复键的字符串:

map3 = new HashMap<>(map1);
for (Map.Entry<String, String> e : map2.entrySet())
map3.merge(e.getKey(), e.getValue(), String::concat);
//or instead of the above loop
map2.forEach((k, v) -> map3.merge(k, v, String::concat));

如果你知道你没有重复的键,并且想要强制它,你可以使用一个merge函数抛出AssertionError:

map2.forEach((k, v) ->
map3.merge(k, v, (v1, v2) ->
{throw new AssertionError("duplicate values for key: "+k);}));

从这个特定的问题后退一步,Java 8流库提供了toMapgroupingBy 收藏家。如果在循环中重复合并映射,则可以重新构造计算以使用流,这既可以澄清代码,又可以使用并行流和并发收集器轻松实现并行。

用于合并两个映射的Java 8替代一行程序:

defaultMap.forEach((k, v) -> destMap.putIfAbsent(k, v));

方法参考也一样:

defaultMap.forEach(destMap::putIfAbsent);

或原始地图解与第三个地图的幂分量:

Map<String, Integer> map3 = new HashMap<String, Integer>(map2);
map1.forEach(map3::putIfAbsent);

下面是用番石榴将两个映射合并为快速不可变映射的方法,该方法执行最少的中间复制操作:

ImmutableMap.Builder<String, Integer> builder = ImmutableMap.<String, Integer>builder();
builder.putAll(map1);
map2.forEach((k, v) -> {if (!map1.containsKey(k)) builder.put(k, v);});
ImmutableMap<String, Integer> map3 = builder.build();

另请参阅用Java 8合并两个映射,了解两个映射中出现的值需要与映射函数组合的情况。

使用Java 8 Stream API的一行程序:

map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue))

该方法的好处之一是能够传递一个merge函数,该函数将处理具有相同键的值,例如:

map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, Math::max))

您可以使用- addAll方法

http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html

但是总会有这样的问题,如果你的两个哈希映射有相同的键,那么它会用第二个哈希映射的键值覆盖第一个哈希映射的键值。

为了安全起见-更改键值-您可以在键上使用前缀或后缀-(第一个哈希映射使用不同的前缀/后缀,第二个哈希映射使用不同的前缀/后缀)

组合两个可能共享公共键的映射的通用解决方案:

就地:

public static <K, V> void mergeInPlace(Map<K, V> map1, Map<K, V> map2,
BinaryOperator<V> combiner) {
map2.forEach((k, v) -> map1.merge(k, v, combiner::apply));
}

返回一个新地图:

public static <K, V> Map<K, V> merge(Map<K, V> map1, Map<K, V> map2,
BinaryOperator<V> combiner) {
Map<K, V> map3 = new HashMap<>(map1);
map2.forEach((k, v) -> map3.merge(k, v, combiner::apply));
return map3;
}

一个小片段,我经常使用从其他地图创建地图:

static public <K, V> Map<K, V> merge(Map<K, V>... args) {
final Map<K, V> buffer = new HashMap<>();


for (Map m : args) {
buffer.putAll(m);
}


return buffer;
}

你可以使用HashMap<String, List<Integer>>来合并两个hashmap,避免丢失与相同键配对的元素。

HashMap<String, Integer> map1 = new HashMap<>();
HashMap<String, Integer> map2 = new HashMap<>();
map1.put("key1", 1);
map1.put("key2", 2);
map1.put("key3", 3);
map2.put("key1", 4);
map2.put("key2", 5);
map2.put("key3", 6);
HashMap<String, List<Integer>> map3 = new HashMap<>();
map1.forEach((str, num) -> map3.put(str, new ArrayList<>(Arrays.asList(num))));
//checking for each key if its already in the map, and if so, you just add the integer to the list paired with this key
for (Map.Entry<String, Integer> entry : map2.entrySet()) {
Integer value = entry.getValue();
String key = entry.getKey();
if (map3.containsKey(key)) {
map3.get(key).add(value);
} else {
map3.put(key, new ArrayList<>(Arrays.asList(value)));
}
}
map3.forEach((str, list) -> System.out.println("{" + str + ": " + list + "}"));

输出:

{key1: [1, 4]}
{key2: [2, 5]}
{key3: [3, 6]}
    HashMap<Integer,String> hs1 = new HashMap<>();
hs1.put(1,"ram");
hs1.put(2,"sita");
hs1.put(3,"laxman");
hs1.put(4,"hanuman");
hs1.put(5,"geeta");


HashMap<Integer,String> hs2 = new HashMap<>();
hs2.put(5,"rat");
hs2.put(6,"lion");
hs2.put(7,"tiger");
hs2.put(8,"fish");
hs2.put(9,"hen");


HashMap<Integer,String> hs3 = new HashMap<>();//Map is which we add


hs3.putAll(hs1);
hs3.putAll(hs2);


System.out.println(" hs1 : " + hs1);
System.out.println(" hs2 : " + hs2);
System.out.println(" hs3 : " + hs3);

重复的项目将不会被添加(即重复的键),因为当我们将打印hs3时,我们将只获得键5的一个值,这将是最后一个添加的值,它将是rat。 **[Set有一个不允许重复键的属性,但是值可以重复]

很晚了,但让我分享一下当我遇到同样的问题时我是怎么做的。

Map<String, List<String>> map1 = new HashMap<>();
map1.put("India", Arrays.asList("Virat", "Mahi", "Rohit"));
map1.put("NZ", Arrays.asList("P1","P2","P3"));


Map<String, List<String>> map2 = new HashMap<>();
map2.put("India", Arrays.asList("Virat", "Mahi", "Rohit"));
map2.put("NZ", Arrays.asList("P1","P2","P4"));


Map<String, List<String>> collect4 = Stream.of(map1, map2)
.flatMap(map -> map.entrySet().stream())
.collect(
Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(strings, strings2) -> {
List<String> newList = new ArrayList<>();
newList.addAll(strings);
newList.addAll(strings2);
return newList;
}
)
);
collect4.forEach((s, strings) -> System.out.println(s+"->"+strings));

它给出以下输出

NZ->[P1, P2, P3, P1, P2, P4]
India->[Virat, Mahi, Rohit, Virat, Mahi, Rohit]

方法1:将映射放在List中,然后连接

public class Test15 {
public static void main(String[] args) {


Map<String, List<String>> map1 = new HashMap<>();
map1.put("London", Arrays.asList("A", "B", "C"));
map1.put("Wales", Arrays.asList("P1", "P2", "P3"));


Map<String, List<String>> map2 = new HashMap<>();
map2.put("Calcutta", Arrays.asList("Protijayi", "Gina", "Gini"));
map2.put("London", Arrays.asList( "P4", "P5", "P6"));
map2.put("Wales", Arrays.asList( "P111", "P5555", "P677666"));
    

System.out.println(map1);System.out.println(map2);
    

    

    

// put the maps in an ArrayList
    

List<Map<String, List<String>>> maplist = new ArrayList<Map<String,List<String>>>();
maplist.add(map1);
maplist.add(map2);
/*
<T,K,U> Collector<T,?,Map<K,U>> toMap(


Function<? super T,? extends K> keyMapper,


Function<? super T,? extends U> valueMapper,


BinaryOperator<U> mergeFunction)
*/
    

Map<String, List<String>> collect = maplist.stream()
.flatMap(ch -> ch.entrySet().stream())
.collect(
Collectors.toMap(
            

//keyMapper,
            

Entry::getKey,
            

//valueMapper
Entry::getValue,
            

// mergeFunction
(list_a,list_b) -> Stream.concat(list_a.stream(), list_b.stream()).collect(Collectors.toList())
            

));
    

    

    

System.out.println("Final Result(Map after join) => " + collect);
/*
{Wales=[P1, P2, P3], London=[A, B, C]}
{Calcutta=[Protijayi, Gina, Gini], Wales=[P111, P5555, P677666], London=[P4, P5, P6]}
Final Result(Map after join) => {Calcutta=[Protijayi, Gina, Gini], Wales=[P1, P2, P3, P111, P5555, P677666], London=[A, B, C, P4, P5, P6]}
*/
    

}//main




}

方法二:法线映射合并

public class Test15 {
public static void main(String[] args) {


Map<String, List<String>> map1 = new HashMap<>();
map1.put("London", Arrays.asList("A", "B", "C"));
map1.put("Wales", Arrays.asList("P1", "P2", "P3"));


Map<String, List<String>> map2 = new HashMap<>();
map2.put("Calcutta", Arrays.asList("Protijayi", "Gina", "Gini"));
map2.put("London", Arrays.asList( "P4", "P5", "P6"));
map2.put("Wales", Arrays.asList( "P111", "P5555", "P677666"));
    

System.out.println(map1);System.out.println(map2);
    

    

    



/*
<T,K,U> Collector<T,?,Map<K,U>> toMap(


Function<? super T,? extends K> keyMapper,


Function<? super T,? extends U> valueMapper,


BinaryOperator<U> mergeFunction)
*/
    

    

Map<String, List<String>> collect = Stream.of(map1,map2)
.flatMap(ch -> ch.entrySet().stream())
.collect(
Collectors.toMap(
            

//keyMapper,
            

Entry::getKey,
            

//valueMapper
Entry::getValue,
            

// mergeFunction
(list_a,list_b) -> Stream.concat(list_a.stream(), list_b.stream()).collect(Collectors.toList())
            

));
    

    

    

System.out.println("Final Result(Map after join) => " + collect);
/*
{Wales=[P1, P2, P3], London=[A, B, C]}
{Calcutta=[Protijayi, Gina, Gini], Wales=[P111, P5555, P677666], London=[P4, P5, P6]}
Final Result(Map after join) => {Calcutta=[Protijayi, Gina, Gini], Wales=[P1, P2, P3, P111, P5555, P677666], London=[A, B, C, P4, P5, P6]}


*/
    

}//main




}
    

在Python中,HashMap被称为字典,我们可以很容易地合并它们。

x = {'Roopa': 1, 'Tabu': 2}
y = {'Roopi': 3, 'Soudipta': 4}




z = {**x,**y}
print(z)
{'Roopa': 1, 'Tabu': 2, 'Roopi': 3, 'Soudipta': 4}

您可以使用putAll函数用于Map,如下面的代码所示

HashMap<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("a", 1);
map1.put("b", 2);
map1.put("c", 3);
HashMap<String, Integer> map2 = new HashMap<String, Integer>();
map1.put("aa", 11);
map1.put("bb", 12);
HashMap<String, Integer> map3 = new HashMap<String, Integer>();
map3.putAll(map1);
map3.putAll(map2);
map3.keySet().stream().forEach(System.out::println);
map3.values().stream().forEach(System.out::println);

下面的代码片段采用多个映射并将它们组合起来。

 private static <K, V> Map<K, V> combineMaps(Map<K, V>... maps) {
if (maps == null || maps.length == 0) {
return Collections.EMPTY_MAP;
}


Map<K, V> result = new HashMap<>();


for (Map<K, V> map : maps) {
result.putAll(map);
}
return result;
}

演示示例链接。

假设输入如下:

    import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.util.Map;
   

...


var m1 = Map.of("k1", 1, "k2", 2);
var m2 = Map.of("k3", 3, "k4", 4);

当你确定两个输入映射之间没有任何键冲突时,一个避免任何突变并产生不可变结果的简单表达式可以是:

    var merged = Stream.concat(
m1.entrySet().stream(),
m2.entrySet().stream()
).collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue));

在可能发生键冲突的情况下,我们可以提供一个lambda来指定如何去重复它们。例如,如果我们想保留最大的值,以防两个输入中都有一个条目,我们可以:

    .collect(Collectors.toUnmodifiableMap(
Map.Entry::getKey,
Map.Entry::getValue,
Math::max))  // any function  (Integer, Integer) -> Integer  is ok here