Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/neo4j/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Java8流API合并地图列表_Java_Lambda_Java 8 - Fatal编程技术网

使用Java8流API合并地图列表

使用Java8流API合并地图列表,java,lambda,java-8,Java,Lambda,Java 8,我试图学习java8流,当我试图将一些函数转换为java8进行实践时。我遇到了一个问题 我很好奇如何将follow代码转换为java流格式 /* * input example: * [ { "k1": { "kk1": 1, "kk2": 2}, "k2": {"kk1": 3, "kk2": 4} } { "k1": { "kk1": 10, "kk2": 20}, "k2": {"kk1": 30,

我试图学习java8流,当我试图将一些函数转换为java8进行实践时。我遇到了一个问题

我很好奇如何将follow代码转换为java流格式

/*
 * input example:
 * [
    {
        "k1": { "kk1": 1, "kk2": 2},
        "k2": {"kk1": 3, "kk2": 4}
    }
    {
        "k1": { "kk1": 10, "kk2": 20},
        "k2": {"kk1": 30, "kk2": 40}
    }
  ]
 * output:
 * {
        "k1": { "kk1": 11, "kk2": 22},
        "k2": {"kk1": 33, "kk2": 44}
   }
 *
 *
 */
private static Map<String, Map<String, Long>> mergeMapsValue(List<Map<String, Map<String, Long>>> valueList) {
    Set<String> keys_1 = valueList.get(0).keySet();
    Set<String> keys_2 = valueList.get(0).entrySet().iterator().next().getValue().keySet();
    Map<String, Map<String, Long>> result = new HashMap<>();
    for (String k1: keys_1) {
        result.put(k1, new HashMap<>());
        for (String k2: keys_2) {
            long total = 0;
            for (Map<String, Map<String, Long>> mmap: valueList) {
                Map<String, Long> m = mmap.get(k1);
                if (m != null && m.get(k2) != null) {
                    total += m.get(k2);
                }
            }
            result.get(k1).put(k2, total);
        }
    }
    return result;
}
/*
*输入示例:
* [
{
“k1”:{“kk1”:1,“kk2”:2},
“k2”:{“kk1”:3,“kk2”:4}
}
{
“k1”:{“kk1”:10,“kk2”:20},
“k2”:{“kk1”:30,“kk2”:40}
}
]
*输出:
* {
“k1”:{“kk1”:11,“kk2”:22},
“k2”:{“kk1”:33,“kk2”:44}
}
*
*
*/
私有静态映射合并映射值(列表值列表){
Set keys_1=valueList.get(0).keySet();
Set keys_2=valueList.get(0).entrySet().iterator().next().getValue().keySet();
映射结果=新的HashMap();
用于(字符串k1:键_1){
put(k1,newhashmap());
用于(字符串k2:键2){
长总计=0;
对于(地图mmap:valueList){
Map m=mmap.get(k1);
如果(m!=null&&m.get(k2)!=null){
总+=m.get(k2);
}
}
结果:get(k1)、put(k2,总计);
}
}
返回结果;
}

作为起点,转换为使用
computeIfAbsent
merge
为我们提供了以下信息:

private static <K1, K2> Map<K1, Map<K2, Long>> mergeMapsValue(List<Map<K1, Map<K2, Long>>> valueList) {
    final Map<K1, Map<K2, Long>> result = new HashMap<>();
    for (final Map<K1, Map<K2, Long>> map : valueList) {
        for (final Map.Entry<K1, Map<K2, Long>> sub : map.entrySet()) {
            for (final Map.Entry<K2, Long> subsub : sub.getValue().entrySet()) {
                result.computeIfAbsent(sub.getKey(), k1 -> new HashMap<>())
                        .merge(subsub.getKey(), subsub.getValue(), Long::sum);
            }
        }
    }
    return result;
}
这就是我想出来的——太可怕了。问题在于,使用
foreach
方法时,您对迭代的每个级别都有一个引用—这使得逻辑变得简单。使用函数的方法,你需要分别考虑每个折叠操作。 它是如何工作的

我们首先
stream()
我们的
列表
,给出一个
。接下来我们将
flatMap
每个元素,给出一个
——因此我们将第一个维度展平。但我们不能进一步扁平化,因为我们需要
K1

然后我们在
K1
值上使用
collect(groupingBy)
,给我们一个
Map
-什么是东西

首先,我们使用
映射(Entry::getValue,toList())
为我们提供
映射。然后我们使用
收集,然后
获取该
列表
,并将其减少。请注意,这意味着我们会生成一个中间的
列表
,这是一种浪费-您可以通过使用自定义的
收集器来解决这个问题

为此,我们使用
List.stream().reduce(a,b)
,其中
a
是初始值,
b
是“折叠”操作
a
设置为
newhashmap()
b
取两个值:初始值或先前应用函数的结果以及
列表中的当前项。因此,对于
列表中的每个项目
使用
Map.merge
组合值


我想说,这种方法或多或少是难以辨认的——你不可能在几个小时内破译它,更不用说几天了。

这里的诀窍是正确收集内部地图。工作流程将是:

  • 将地图
    list
    列表平面映射到地图条目流
    stream
  • 按每个条目的键分组,对于映射到同一键的值,将两个映射合并在一起
通过合并地图来收集地图在理想情况下需要一个
flatMapping
收集器,但不幸的是,Java 8中不存在这个收集器(请参阅)。对于Java8,可以使用库提供的(并在下面的代码中使用)

私有静态映射合并映射值(列表值列表){
返回valueList.stream()
.flatMap(e->e.entrySet().stream())
.collect(收集器.groupingBy(
Map.Entry::getKey,
平面映射(
e->e.getValue().entrySet().stream(),
toMap(Map.Entry::getKey,Map.Entry::getValue,Long::sum)
)
));
}
如果不使用这个方便的收集器,我们仍然可以使用等效语义构建自己的收集器:

private static Map<String, Map<String, Long>> mergeMapsValue2(List<Map<String, Map<String, Long>>> valueList) {
    return valueList.stream()
                    .flatMap(e -> e.entrySet().stream())
                    .collect(Collectors.groupingBy(
                        Map.Entry::getKey,
                        Collector.of(
                            HashMap::new,
                            (r, t) -> t.getValue().forEach((k, v) -> r.merge(k, v, Long::sum)),
                            (r1, r2) -> { r2.forEach((k, v) -> r1.merge(k, v, Long::sum)); return r1; }
                        )
                    ));
}
private静态映射mergeMapsValue2(列表值列表){
返回valueList.stream()
.flatMap(e->e.entrySet().stream())
.collect(收集器.groupingBy(
Map.Entry::getKey,
收藏(
HashMap::新建,
(r,t)->t.getValue().forEach((k,v)->r.merge(k,v,Long::sum)),
(r1,r2)->{r2.forEach((k,v)->r1.merge(k,v,Long::sum));返回r1;}
)
));
}
我从Tunaki获取了
flatMap(e->e.entrySet().stream())
部分,但为收集器使用了一个较短的变量:

Map<String, Integer> merged = maps.stream()
  .flatMap(map -> map.entrySet().stream())
  .collect(Collectors.toMap(
    Map.Entry::getKey, Map.Entry::getValue, Integer::sum));
Map merged=maps.stream()
.flatMap(map->map.entrySet().stream())
.collect(collector.toMap)(
Map.Entry::getKey,Map.Entry::getValue,Integer::sum));
更详细的例子:

Map<String, Integer> a = new HashMap<String, Integer>() {{
  put("a", 2);
  put("b", 5);
}};
Map<String, Integer> b = new HashMap<String, Integer>() {{
  put("a", 7);
}};
List<Map<String, Integer>> maps = Arrays.asList(a, b);

Map<String, Integer> merged = maps.stream()
  .flatMap(map -> map.entrySet().stream())
  .collect(Collectors.toMap(
    Map.Entry::getKey, Map.Entry::getValue, Integer::sum));

assert merged.get("a") == 9;
assert merged.get("b") == 5;
Map a=newhashmap(){{
付诸表决(“a”,2);
付诸表决(“b”,5);
}};
Map b=新的HashMap(){{
付诸表决(“a”,7);
}};
列表映射=数组.asList(a,b);
Map merged=maps.stream()
.flatMap(map->map.entrySet().stream())
.collect(collector.toMap)(
Map.Entry::getKey,Map.Entry::getValue,Integer::sum));
assert merged.get(“a”)==9;
assert merged.get(“b”)==5;

所以所有地图都是相同的-即在两个级别都有相同的键?这不是代码翻译服务。你需要向我们展示你已经尝试过的东西,这样我们才能告诉你你做错了什么。你应该首先重新思考你最初的方法,即在外循环中迭代什么,在内循环中迭代什么。@Holger我知道我应该先想一想,但是我完全找不到完成它的方法。我偷了你的
Long::sum
-我一直忘了它的存在。我认为你的
Stream
方法总体上更好,因为
Map<String, Integer> merged = maps.stream()
  .flatMap(map -> map.entrySet().stream())
  .collect(Collectors.toMap(
    Map.Entry::getKey, Map.Entry::getValue, Integer::sum));
Map<String, Integer> a = new HashMap<String, Integer>() {{
  put("a", 2);
  put("b", 5);
}};
Map<String, Integer> b = new HashMap<String, Integer>() {{
  put("a", 7);
}};
List<Map<String, Integer>> maps = Arrays.asList(a, b);

Map<String, Integer> merged = maps.stream()
  .flatMap(map -> map.entrySet().stream())
  .collect(Collectors.toMap(
    Map.Entry::getKey, Map.Entry::getValue, Integer::sum));

assert merged.get("a") == 9;
assert merged.get("b") == 5;