将 hashmap 列表按相同的顺序连接成一个,而不覆盖密钥

Concatenate a list of hashmap into one on the same otder they are and without overwriting the key

我正在学习 Java 语言并找到了这个练习。我知道他们想以相同的顺序将 hashmap 列表连接到一个 hashmap 中并且不覆盖密钥,但是我不理解这些示例所以我没有找到他们所说的排列所以我认为我的理解是错误的. 你能给我解释一下它们是如何工作的吗?

Concatenate Map

This function will be given a single parameter known as the Map List. The Map List is a list of maps. Your job is to combine all the maps found in the map list into a single map and return it. There are two rules for adding values to the map.

You must add key-value pairs to the map in the same order they are found in the Map List. If the key already exists, it cannot be overwritten. In other words, if two or more maps have the same key, the key to be added cannot be overwritten by the subsequent maps.
Signature:

public static HashMap<String, Integer> concatenateMap(ArrayList<HashMap<String, Integer>> mapList)

示例:

INPUT: [{b=55, t=20, f=26, n=87, o=93}, {s=95, f=9, n=11, o=71}, {f=89, n=82, o=29}]
OUTPUT: {b=55, s=95, t=20, f=26, n=87, o=93}
INPUT: [{v=2, f=80, z=43, k=90, n=43}, {d=41, f=98, y=39, n=83}, {d=12, v=61, y=44, n=30}]
OUTPUT: {d=41, v=2, f=80, y=39, z=43, k=90, n=43}
INPUT: [{p=79, b=10, g=28, h=21, z=62}, {p=5, g=87, h=38}, {p=29, g=44, x=59, y=8, z=82}]
OUTPUT: {p=79, b=10, g=28, h=21, x=59, y=8, z=62}
public static void main(String[] args) {

    //{b=55, t=20, f=26, n=87, o=93}, {s=95, f=9, n=11, o=71}, {f=89, n=82, o=29}
    HashMap<String, Integer> map1 = new HashMap<>();
    map1.put("b", 55);
    map1.put("t", 20);
    map1.put("f", 26);
    map1.put("n", 87);
    map1.put("o", 93);

    HashMap<String, Integer> map2 = new HashMap<>();
    map2.put("s", 95);
    map2.put("f", 9);
    map2.put("n", 11);
    map2.put("o", 71);

    HashMap<String, Integer> map3 = new HashMap<>();
    map3.put("f", 89);
    map3.put("n", 82);
    map3.put("o", 29);

    ArrayList<HashMap<String, Integer>> list = new ArrayList<>();
    list.add(map1);
    list.add(map2);
    list.add(map3);

    HashMap<String, Integer> flat = concatenateMap(list);

    System.out.println(flat.toString());

}

public static HashMap<String, Integer> concatenateMap(ArrayList<HashMap<String, Integer>> mapList){

    HashMap<String, Integer> result = new HashMap<>();

    //iterate all maps
    for(HashMap<String, Integer> map : mapList){

        //iterate all keys from map
        for(String key : map.keySet()){

            //if result already contains key, skip
            if(result.containsKey(key)){
                continue;
            }

            result.put(key, map.get(key));

        }

    }

    return result;

}

试试这个。

public static Map<String, Integer> concatenateMap(List<Map<String, Integer>> list) {
    Map<String, Integer> result = new HashMap<>();
    for (Map<String, Integer> map : list)
        for (Entry<String, Integer> e : map.entrySet())
            result.computeIfAbsent(e.getKey(), k -> e.getValue());
    return result;
}

并测试:

Map<String, Integer> actual = concatenateMap(List.of(
    Map.of("b", 55, "t", 20, "f", 26, "n", 87, "o", 93),
    Map.of("s", 95, "f", 9, "n", 11, "o", 71),
    Map.of("f", 89, "n", 82, "o", 29)));
Map<String, Integer> expected =
    Map.of("b", 55, "s", 95, "t", 20, "f", 26, "n", 87, "o", 93);
System.out.println(actual.equals(expected) ? "OK" : "NG");
// -> OK

如果您使用的是 Java 8 或更高版本:

public static HashMap<String, Integer> concatenateMap(ArrayList<HashMap<String, Integer>> mapList){

    HashMap<String, Integer> result = new HashMap<>();
    mapList.stream().flatMap(map -> map.entrySet().stream()).forEachOrdered(m -> {
        result.putIfAbsent(m.getKey(), m.getValue());
    });
    return result;
}

首先请阅读这个问题中还有两个参考文献,对HashMap的解释更详细。

除了HashMap,在你的问题中你还有ArrayList,其中有HashMap。所以有具有如下值的HaspMaps(要将值添加到HashMap,有方法put(Key, Value)):

    HashMap<String, Integer> map1 = new HashMap<>();
    map1.put("b", 55);
    map1.put("t", 20);
    map1.put("f", 26);
    map1.put("n", 87);
    map1.put("o", 93);

    HashMap<String, Integer> map2 = new HashMap<>();
    map2.put("s", 95);
    map2.put("f", 9);
    map2.put("n", 11);
    map2.put("o", 71);

    HashMap<String, Integer> map3 = new HashMap<>();
    map3.put("f", 89);
    map3.put("n", 82);
    map3.put("o", 29);

所有这些 HashMap 都存储在 ArrayList 中,如下所示:

    ArrayList<HashMap<String, Integer>> list = new ArrayList<>();
    list.add(map1);
    list.add(map2);
    list.add(map3);

在你的问题中写着:

This function will be given a single parameter known as the Map List

所以listobject就是上面说的单参数。现在我们将把这个参数传递给一个函数,该函数连接所有映射(不覆盖任何现有键)和 returns 一个 HashMap。这是函数:

    public static HashMap<String, Integer> concatenateMap(ArrayList<HashMap<String, Integer>> mapList){
        HashMap<String, Integer> map = mapList.get(0);

        for (int i = 1; i < mapList.size(); ++i) {
            for (Map.Entry<String, Integer> m : mapList.get(i).entrySet()) {
                if (!map.containsKey(m.getKey())) map.put(m.getKey(), m.getValue());
            }
        }

        return map;
    }

所以在这个函数中创建了一个 map 并且列表的第一个元素直接分配给它,这样我们可以跳过第一次迭代,因为键在每个 HashMap 中都是唯一的,无论如何第一个 HashMap 的所有元素将在 map 中添加。之后我们从第二个元素 (int i = 1) 开始,迭代每个 HashMap。我们还有内部循环,我们在其中迭代每个 HashMap 的元素(键、值对)。最后我们检查每个键在我们的 map 对象中是否存在,如果它已经在地图中,我们跳过它不覆盖,否则我们添加它。循环后,我们 return 我们的 map 对象。

使用Stream非常简单,第三个参数(i1, i2) -> i1)允许在键重复的情况下选择第一个值

static Map<String, Integer> concatenateMap(List<Map<String, Integer>> mapList) {
    return mapList.stream().map(Map::entrySet).flatMap(Set::stream)
                  .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (i1, i2) -> i1));
}