特定键的映射中的值的总和

时间:2015-11-09 12:26:03

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

我的文本文件中包含一个文件,每行包含一对名称和金额,如下所示:

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();
    }
    ;

}

实际上我是如何以更多功能的方式改进此代码,同时更多地同时处理数据(使用并行流等)

1 个答案:

答案 0 :(得分:9)

当您想编写功能代码时,规则是:不要使用<ul><<li><span>test</span></li></ul> 。这是一个必不可少的解决方案,并打破了功能代码。

你想要的是按第一部分(键)分割每一行和一组,同时总结第二部分(值):

 $cNodes = $node->childNodes;
        if (count($cNodes) > 0) {
            foreach ($cNodes as $cNode) {              
                // Added to get tables to work                    
                $htmlContainers = array(
                    'tbody',
                    'tr',
                    'td',
                    'p',
                    'span'

                );
                if (in_array( $cNode->nodeName, $htmlContainers ) ) {                        
                    self::parseNode($cNode, $element, $styles, $data);
                } else{                    
                    // All other containers as defined in AbstractContainer
                    if ($element instanceof AbstractContainer) {                        
                        self::parseNode($cNode, $element, $styles, $data);
                    }
                }  
            }
        }

在此代码中,我们分割每一行。然后,我们使用Collectors.groupingBy(classifier, downstream)对流进行分组,其中:

  • 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])))); 的键的函数,只返回行的第一部分
  • classifier是一个收集器,可以减少具有相同键的每个值:在这种情况下,它是Collectors.summingInt(mapper),它对给定映射器提取的每个整数求和。

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

downstream

如果此键不存在,这将使用值forEach添加值map.merge(line[0], Integer.valueOf(line[1]), Integer::sum); 的新值,否则,它将使用给定的重新映射函数(它是在这种情况下的新旧价值)。