Search code examples
javajava-streamjava-collections-api

java 8 stream how to map 2 column into the map


I have a table:

name | data | num
item1 | 16 | 2
item2 | 17 | 3
item1 | 16 | 5

I would like to transform it to:

{ item1: {16+16, 2+5}, item2: {17, 3}}

However I only succeed to produce the following result:

{ item1: 16+16, item2: 17}

with the following code: The Stats class store both fields, but I don't know how to add both fields into the data

class Stats {
    public Integer data, num;
    public Stats(Integer td, Integer nf) {
        data = td;
        num = nf;
    }
    public Integer getdata(){
        return data;
    }
    public Integer getnum(){
        return num;
    }
}
Map<String, Stats> map = new HashMap<>();
Stream<String> lines = Files.lines(Paths.get(table));
map = lines.map(x -> 
             .collect(Collectors.toMap(
                z -> z[0],
                z -> Integer.parseInt(z[1]),
                (a, b) -> a+b));

The above code only works for Map<String, Int> since I'm not sure how to make Map<String, Stats> works. Any idea how to get the item on the second column into the map while and using 1 pipeline only?


Solution

  • Here's an implementation that:

    • doesn't need any extra classes
    • works for any length of numeric values (not just 2)
    • is (technically) just one line


    Stream<String> lines = Stream.of("item1,16,2",
          "item2,17,3",
          "item1,16,5"); // sample input
    
    Map<String, List<Integer>> map = lines.map(s -> s.split(","))
      .collect(Collectors.toMap(a -> a[0],
          a -> Arrays.asList(a).stream()
           .skip(1).map(Integer::parseInt)
            .collect(Collectors.toList()),
          (a, b) -> {for (int i = 0; i < a.size(); i++)
              a.set(i, a.get(i) + b.get(i)); return a;}));
    

    Printing the map after running this outputs:

    {item2=[17, 3], item1=[32, 7]}
    

    See live demo of this code.