Home » Java » java – Sum content of list which has the same content-Exceptionshub

java – Sum content of list which has the same content-Exceptionshub

Posted by: admin February 25, 2020 Leave a comment

Questions:

I have a sortedList from type “Details” which has the following content:

[0]=Details test0: 28.01.2020
[0]=Details test1: 1234
[0]=Details test2: abcd
[0]=Details test3: 1
[0]=Details test4: 20.6
[0]=Details test5: 20.20

[1]=Details test0: 28.01.2020
[1]=Details test1: 1234
[1]=Details test2: abcd
[1]=Details test3: 1
[1]=Details test4: 20.6
[1]=Details test5: 20.20

[2]=Details test0: 29.01.2020
[2]=Details test1: 1234
[2]=Details test2: abcd
[2]=Details test3: 1
[2]=Details test4: 20.7
[2]=Details test5: 20.20

Now the sorted list returns all this objects but I want to sum up all with the same test0,test1,test2 and sum test3,test4 and test5 (test3+test3, test4+test4 and test5+test5):

[0]=Details test0: 28.01.2020
[0]=Details test1: 1234
[0]=Details test2: abcd
[0]=Details test3: 2
[0]=Details test4: 41.2
[0]=Details test2: 40.40

[1]=Details test0: 29.01.2020
[1]=Details test1: 1234
[1]=Details test2: abcd
[1]=Details test3: 1
[1]=Details test4: 2.7
[1]=Details test5: 20.20

I’m not sure if list.stream().filter is the best option for this problem. Any ideas?
two methods that should find all test0 duplicates:

    public static List<Detail> getDuplicates(final List<Detail> list) {
    return getDuplicatesMap(list).values()
        .stream()
        .filter(duplicates -> duplicates.size() > 1)
        .flatMap(Collection::stream)
        .collect(Collectors.toList());
}

private static Map<String, List<Details>> getDuplicatesMap(List<Details> list) {
    return list.stream().collect(Collectors.groupingBy(Details::test0));
}
How to&Answers:

Well, until we know what ‘sum the properties’ means, all I can do is give you a quick example of how to sum things sharing the same ‘test number’.

final List<Details> detailses = ...; // Whatever you currently have.

detailses.stream()

        // Group by 'test number'.
        // This will return a Map<Integer, List<Details>>
        // The key is the test number, and the List contains all matching Details
        .collect(Collectors.groupingBy(Details::getTestNumber))

        // Stream over the entries of this grouped map
        .entrySet().stream()

        // And collect it to another Map
        .collect(Collectors.toMap(
            Map.Entry::getKey, // Keys stay the same

            // Values are mapped to the 'sum' of the properties...
            // However you choose to define that
            entry -> entry.getValue().stream()
                    .map(Details::getProperty)
                    .collect(/* Define summing the property here ... */)
        ));

This will result in a Map<Integer, ?> where the keys are the test numbers, and the values are the ‘sum’ of all the properties for Details with that test number.

Answer:

What you are looking for is merging duplicate entries based on a few attributes and not just identifying the duplicates. Using Collectors.toMap with a mergeFunction should help you resolve this.

public static List<Details> getDuplicates(final List<Details> list) {
    return new ArrayList<>(list.stream()
            .collect(Collectors.toMap(dtl -> 
                            Arrays.asList(dtl.getTest0(), dtl.getTest1(), dtl.getTest2()), 
                    Function.identity(), Details::mergeDuplicates))
            .values());
}

where the merge function is assumed to be using type-specific Numbers that can be added as in:

static Details mergeDuplicates(Details a, Details b) {
    return new Details(a.getTest0(), a.getTest1(), a.getTest2(),
            a.getTest3() + b.getTest3(), a.getTest4() + b.getTest4(), a.getTest5() + b.getTest5());
}