Home > front end >  In ArrayList, group by a key and perform summation over one of the values
In ArrayList, group by a key and perform summation over one of the values

Time:09-23

I have a list of Student objects.

It is required to get create a new list which should be having sum of their marks.

Preferred if this can be done using Java-8

public class Test {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student(1, "A", 10));
        list.add(new Student(1, "A", 20));
        list.add(new Student(1, "A", 10));
        list.add(new Student(1, "A", 30));
        list.add(new Student(2, "B", 40));
        list.add(new Student(2, "B", 50));

        Map<String, List<Student>> map = list
                .stream()
                .collect(Collectors.groupingBy(Student::getName));
        System.out.println(map);  // not getting desired result
        
        // Expected Output
        // list [{1, "A", 70}, {2, "B", 90}]

    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Student {
    int id;
    String name;
    int marks;
}

I get below exception

Exception in thread "main" java.lang.IllegalStateException: Duplicate key 1 (attempted merging values Student(id=1, name=A, marks=10) and Student(id=1, name=A, marks=20))
    at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:135)
    at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:182)
    at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
    at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
    at com.tara.cas.service.Test.main(Test.java:22)

CodePudding user response:

public class Test {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student(1, "A", 10));
        list.add(new Student(1, "A", 20));
        list.add(new Student(1, "A", 10));
        list.add(new Student(1, "A", 30));
        list.add(new Student(2, "B", 40));
        list.add(new Student(2, "B", 50));

        Map<Integer, Student> map = list.stream().collect(Collectors.toMap(Student::getId, Function.identity(),
                (existing, replacement) -> {
                    existing.setMarks(existing.getMarks() replacement.getMarks());
                    return existing;
                }));

        System.out.println(map.values());
    }
}

class Student {
    int id;
    String name;
    int marks;

    public Student(int id, String name, int marks) {
        this.id = id;
        this.name = name;
        this.marks = marks;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getMarks() {
        return marks;
    }

    public void setMarks(int marks) {
        this.marks = marks;
    }

    @Override
    public String toString() {
        return "{" id ", \"" name "\", " marks "}";
    }
}

Output:

[{1, "A", 70}, {2, "B", 90}]
  • Related