【问题标题】:Sum of values in the map for specific key映射中特定键的值总和
【发布时间】:2016-02-10 02:18:31
【问题描述】:

我有一个文本文件,其中每一行都包含一对名称和数量,如下所示:

Mike 5
Kate 2
Mike 3

我需要按键对这些值求和。我是这样解决的

public static void main(String[] args) {
    Map<String, Integer> map = new HashMap<String, Integer>();
    try {
        Files.lines(Paths.get("/Users/walter/Desktop/stuff.txt"))
                .map(line -> line.split("\\s+")).forEach(line -> {
                    String key = line[0];
                    if (map.containsKey(key)) {
                        Integer oldValue = map.get(key);
                        map.put(key, oldValue + Integer.parseInt(line[1]));
                    } else {
                        map.put(line[0], Integer.parseInt(line[1]));
                    }
                });
        map.forEach((k,v) -> System.out.println(k + " " +v));

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    ;

}

实际上,我如何以更实用的方式改进此代码,使其能够更并发地处理数据(使用并行流等)

【问题讨论】:

    标签: java hashmap refactoring java-8 java-stream


    【解决方案1】:

    当你要写函数式代码时,规则是:不要使用forEach。这是一个命令式解决方案,会破坏函数式代码。

    您想要的是按第一部分(键)分割每一行和分组,同时对第二部分(值)求和:

    Map<String, Integer> map = 
        Files.lines(Paths.get("/Users/walter/Desktop/stuff.txt"))
             .map(s -> s.split("\\s+"))
             .collect(groupingBy(a -> a[0], summingInt(a -> Integer.parseInt(a[1]))));
    

    在这段代码中,我们拆分了每一行。然后,我们使用 Collectors.groupingBy(classifier, downstream) 对 Stream 进行分组,其中:

    • classifier,这是一个对每个项目进行分类以提取结果Map的key的函数,只返回该行的第一部分
    • downstream 是一个收集器,它减少具有相同键的每个值:在这种情况下,它是 Collectors.summingInt(mapper),它将给定映射器提取的每个整数相加。

    作为旁注(您知道),您可以更简单地使用新的Map.merge(key, value, remappingFunction) 方法重写整个forEach,只需调用:

    map.merge(line[0], Integer.valueOf(line[1]), Integer::sum);
    

    如果此键不存在,这将使用键 line[0] 与值 Integer.valueOf(line[1]) 放置一个新值,否则,它将使用给定的重映射函数更新键(这是旧和新的总和)在这种情况下的价值)。

    【讨论】:

    • 很好的解释!那么示例中的并发处理(并行流使用)呢?
    • @GerardRozsavolgyi 我不确定读取文件中的行是否会很好地并行化,但这只是在 Stream 管道上调用 parallel() 的问题。也许最好收集一个 List 中的所有行并在该 List 上调用 parallelStream() 以按行的第一部分对其进行分组。
    猜你喜欢
    • 1970-01-01
    • 2019-11-10
    • 1970-01-01
    • 1970-01-01
    • 2020-03-21
    • 2021-06-19
    • 1970-01-01
    • 1970-01-01
    • 2021-10-13
    相关资源
    最近更新 更多