0

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"},

    ... 
]
1
  • 1
    What have you tried so far? I would suggest that you iterate through the list once and save the highest score for each studentId using a Map, and the iterate a second time and remove the elements that do not match what is stored in the map. Commented Jul 12, 2018 at 13:18

2 Answers 2

1

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]]}

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you so much, that's what I want! Stream is more efficient than iterating a map twice, thanks!
I have added an example @haohuily.
1

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.

1 Comment

Nice solution ! The problem with this is you create a Map<String, Integer>, you loose the instance information. If you also want to know the course and date of this best result, you will need to search the student again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.