Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

What's the most efficient way to combine objects in a list?

Let’s say I have the following list.

List<StringInteger> test = new ArrayList<>(); //StringInteger is just a pojo with String and int
test.add(new StringInteger("a", 1));
test.add(new StringInteger("b", 1));
test.add(new StringInteger("a", 3));
test.add(new StringInteger("c", 1));
test.add(new StringInteger("a", 1));
test.add(new StringInteger("c", -1));

System.out.println(test); //[{ a : 1 }, { b : 1 }, { a : 3 }, { c : 1 }, { a : 1 }, { c : -1 }]

I need to write a method that would unite items by String key and add integers. So that the result list would be [{ a : 5 }, { b : 1 }, { c : 0 }]

I could do it using HashMap, but if I go that way – I’ll have to create a Map, then use foreach with if(containsKey(...)) and then convert it back to List. It just seems like an overkill.

Is there more elegant solution? I thought that flatMap from Stream API should do the thing, but I cannot figure out how.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

UPD:

Here’s my clumsy solution. It works, but I believe that it can be done more simple than that.

Map<String, Integer> map = new HashMap<>();
for (StringInteger stringInteger : test) {
    if (map.containsKey(stringInteger.getKey())) {
        int previousValue = map.get(stringInteger.getKey());
        map.put(stringInteger.getKey(), previousValue + stringInteger.getValue());
    } else {
        map.put(stringInteger.getKey(), stringInteger.getValue());
    }
}

List<StringInteger> result = map.entrySet().stream().map(stringIntegerEntry -> new StringInteger(stringIntegerEntry.getKey(), stringIntegerEntry.getValue())).collect(Collectors.toList());
System.out.println(result); //[{ a : 5 }, { b : 1 }, { c : 0 }]

>Solution :

As @Louis Wasserman said in the comment HashMap is the right tool for this task.

To translate the hole code into a stream, you can use the built-in collector groupingBy() in conjunction with summingInt as the downstream collector grouping.

result = test.stream()
    .collect(Collectors.groupingBy(   // creates an intermediate map Map<String, Integer>
        StringInteger::getKey,                         // mapping a key
        Collectors.summingInt(StringInteger::getValue) // generating a value
    ))
    .entrySet().stream()
    .map(entry -> new StringInteger(entry.getKey(), entry.getValue()))
    .toList();
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading