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.)
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With