我有一个文件,文件在每行包含一对名称和金额,如下所示:
Mike 5 Kate 2 Mike 3
我需要按键对这些值求和.我以这种方式解决了这个问题
public static void main(String[] args) { Mapmap = new HashMap (); 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(); } ; }
实际上我是如何以更多功能的方式改进这个代码,同时更多地同时处理数据(使用并行流等)
当您想编写功能代码时,规则是:不要使用forEach
.这是一个必不可少的解决方案,并打破功能代码.
你想要的是按第一部分(键)分割每一行和组,同时总结第二部分(值):
Mapmap = 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
,只返回行的第一部分
downstream
是一个收集器,它减少具有相同键的每个值:在这种情况下,它是Collectors.summingInt(mapper)
对给定映射器提取的每个整数求和.
作为旁注(并且你知道),你可以forEach
使用新Map.merge(key, value, remappingFunction)
方法更简单地重写整个方法,只需调用:
map.merge(line[0], Integer.valueOf(line[1]), Integer::sum);
这将会把一个新值与键line[0]
与值Integer.valueOf(line[1])
,如果该键不存在,否则,它会更新与给定的重映射功能键(在这种情况下,新旧价值的总和).