tm1701
tm1701

Reputation: 7581

Combine similar elements in a Java Stream

How to combine consecutive similar objects that are in a Java Stream?

Till now I could not find a good solution, so I hope you can help.

Suppose we have a class like the following:

class Someclass {
     String type;
     int count;
}

When having a Stream { "a", 1 }, { "a", 2}, { "b", 4}, { "b", "5" } and that needs to be processed as { "a", 3 }, { "b", 9 }.

Combining means of course, adding the counts for the objects with the same type.

How to do?

Upvotes: 0

Views: 152

Answers (2)

WJS
WJS

Reputation: 40034

Assume you had a list of maps as in your example.

  • first stream the list
  • then flatten all the entrySets into a single stream.
  • the collect each key/value pair
  • use the (a,b)->a+b merge function to add values for duplicate keys.
List<Map<String, Integer>> maps = List.of(Map.of("a", 1),
        Map.of("a", 2), Map.of("b", 4), Map.of("b", 5));
Map<String, Integer> result =
        maps.stream().flatMap(m -> m.entrySet().stream())
                .collect(Collectors.toMap(Entry::getKey,
                        Entry::getValue, (a, b) -> a + b));
System.out.println(result);

Prints

{a=3, b=9}

If you had an array of objects, you could do it as follows. The compute method puts the value there if it isn't present, or adds to the existing one if it is present.

Object[] values = {"a",1,"b",4,"a",2,"b",5};
Map<String,Integer> map1 = new HashMap<>();
for (int i = 0; i < values.length-1; i+=2) {
    Integer val = (Integer)values[i+1];
    map1.compute((String)values[i], (k,v)->v == null ? val : v +val); 
}

System.out.println(map1);

Upvotes: 2

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79035

You can use Collectors.toMap to collect the stream into the desired Map.

Demo:

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

class MyType {
    String type;
    int count;

    public MyType(String type, int count) {
        this.type = type;
        this.count = count;
    }

    public String getType() {
        return type;
    }

    public int getCount() {
        return count;
    }
}

public class Main {
    public static void main(String[] args) {
        List<MyType> list = List.of(new MyType("a", 1), 
                                    new MyType("a", 2), 
                                    new MyType("b", 4), 
                                    new MyType("b", 5));

        Map<String, Integer> map = list.stream()
                .collect(Collectors.toMap(MyType::getType, MyType::getCount, Integer::sum));

        System.out.println(map);
    }
}

Output:

{a=3, b=9}

Upvotes: 2

Related Questions