haohuily
haohuily

Reputation: 53

Java List sort and group using Stream

I have a List<Records> =

[
    {"studentId": "001", "date": "20180705", "courseId": "CS220", "score": "80"},
    {"studentId": "001", "date": "20180702", "courseId": "CS320", "score": "75"},
    {"studentId": "001", "date": "20180704", "courseId": "CS330", "score": "90"},

    {"studentId": "002", "date": "20180703", "courseId": "CS640", "score": "95"},
    {"studentId": "002", "date": "20180628", "courseId": "CS530", "score": "80"},
    {"studentId": "002", "date": "20180701", "courseId": "CS545", "score": "90"},

    {"studentId": "100", "date": "20180708", "courseId": "CS542", "score": "80"},
    {"studentId": "100", "date": "20180629", "courseId": "CS240", "score": "97"},

    ... 
]

How can I group the objects by same studentId and just keep the one which has highest score in list? like following: List<Records> =

[
    {"studentId": "001", "date": "20180704", "courseId": "CS330", "score": "90"},

    {"studentId": "002", "date": "20180703", "courseId": "CS640", "score": "95"},

    {"studentId": "100", "date": "20180629", "courseId": "CS240", "score": "97"},

    ... 
]

Upvotes: 0

Views: 216

Answers (2)

AxelH
AxelH

Reputation: 14572

Using a Stream to collect the value. You can find an example on Baeldung -- Guide to Java 8 groupingBy Collector

2.8. Getting the Maximum or Minimum from Grouped Results

This could be used like :

records.stream()
    .collect(
         Collectors.groupingBy(
             Record::getStudentId, 
             Collectors.maxBy(Compartor.comparingInt(Record::getPoint))
         )
    );

The map returned will have each studentId as a key and the instance with the maximum value. Example using a POJO :

class POJO {
    String name;
    int value;

    //getters
    //toString //POJO [%name% %value%]
}

And the quick test :

Map<String, Optional<POJO>> map = Stream.of(
            new POJO("A", 1), new POJO("A", 2), new POJO("A", 10),
            new POJO("B", 8), new POJO("B", 4),
            new POJO("C", 4),
            new POJO("D", 4), new POJO("D", 1), new POJO("D", 2)
            ).collect(
                    Collectors.groupingBy(
                            POJO::getName, 
                            Collectors.maxBy(
                                    Comparator.comparingInt(POJO::getValue)
                            )
                    )
            );

    System.out.println(map);

{A=Optional[POJO [A 10]],
B=Optional[POJO [B 8]],
C=Optional[POJO [C 4]],
D=Optional[POJO [D 4]]}

Upvotes: 1

csenga
csenga

Reputation: 4114

This can be done with java8's stream.

    records.stream()
.collect(Collectors.toMap(Records::getStudentId ,Records::getScore,(s1,s2)->Math.max(s1,s2)))

The 3rd param (merge function) of the toMap method always selects the greater score value.

Upvotes: 1

Related Questions