Reputation: 309
I have text file with a file that on every line contain pair of name and amount like this:
Mike 5
Kate 2
Mike 3
I need to sum these values by key. I resolved this in this way
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();
}
;
}
How actually I could improve this code in more functional way, with abillity to process data more concurrently (using parallel streams, etc.)
Upvotes: 4
Views: 2854
Reputation: 137084
When you want to write functional code, the rule is: don't use forEach
. This is an imperative solution and breaks functional code.
What you want is to split each line and group by the first part (key) while summing the second part (values):
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]))));
In this code, we are splitting each line. Then, we are grouping the Stream using Collectors.groupingBy(classifier, downstream)
where:
classifier
, which is a function that classifies each item to extract the key of the resulting Map
, just returns the first part of the linedownstream
is a collector that reduces each value having the same key: in this case, it is Collectors.summingInt(mapper)
which sums each integer extracted by the given mapper.As a side-note (and just so you know), you could rewrite your whole forEach
more simply using the new Map.merge(key, value, remappingFunction)
method, with just a call to:
map.merge(line[0], Integer.valueOf(line[1]), Integer::sum);
This will put a new value with the key line[0]
with the value Integer.valueOf(line[1])
if this key did not exist, otherwise, it will update the key with the given remapping function (which is the sum of the old and new value in this case).
Upvotes: 9