Home > other >  Select the person with the lowest score using java stream
Select the person with the lowest score using java stream

Time:11-23

I have the json above:

[
    {
        "name": "Jonh",
        "scores": [{"score": 6 }, {"score": 4}]
    },
    {
        "name": "David",
        "scores": [{"score": 3}, { "score": 8}]
    }
]

My class:

public class Person
    private String name;
    private Collection<Score> scores;
// getters/setters
}

public class Score{
    private Integer score;
// getters/setters
}

If there was only one person, I would do the code below to get the lowest score:

Score s = list.stream()
              .min(Comparator.comparingInt(Score::getScore))
              .get();

But to get the person with the lowest score using stream, I had no success.
I need to select the person who has the lowest score using java 8 and stream.
What is the most suitable solution?

CodePudding user response:

To find a single person with minimal score it is possible to apply min(Comparator.comparingInt) to the collection of scores:

List<Person> persons = Arrays.asList(
        new Person("John", Arrays.asList(new Score(6), new Score(4))),
        new Person("David", Arrays.asList(new Score(3), new Score(8))),
        new Person("Mark", Arrays.asList(new Score(5), new Score(3)))
);

Person minScored = persons.stream()
       .min(Comparator.comparingInt(p -> p.getScores().stream()
               .mapToInt(Score::getScore).min().orElse(-1)
       ))
       .orElse(null);

System.out.println(minScored);

Output:

Person(name=David, scores=[Score(score=3), Score(score=8)])

However, there could be many Person instances having the minimal score, them it would be better to find first this minimal score and then filter the list of persons:

Score minScore = persons.stream()
                        .flatMap(p -> p.getScores().stream())
                        .min(Comparator.comparingInt(Score::getScore))
                        .orElse(null);

System.out.println("----");
System.out.println("Min Score: "   minScore);
List<Person> mins = persons.stream()
                           .filter(p -> p.getScores().contains(minScore))
                           .collect(Collectors.toList());
mins.forEach(System.out::println);

Output:

----
Min Score: Score(score=3)
Person(name=David, scores=[Score(score=3), Score(score=8)])
Person(name=Mark, scores=[Score(score=5), Score(score=3)])

CodePudding user response:

Simple solution would be to add person field to score. By that you can find lowest score, you can find person with lowest score.

So step one add that field. If that can't be done, create another class that extends score class and add it there.

Then, map lowest score of all people and then, find the lowest score and whoala!

Here is my show implemntation.

public class Test {

public static void main(final String[] args) {
    final Person person1 = new Person("mihajlo");
    person1.getScores().addAll(List.of(new Score(14, person1), new Score(5, person1)));
    final Person person2 = new Person("samuel");
    person2.getScores().addAll(List.of(new Score(1, person2), new Score(50, person2)));
    final List<Person> personList = List.of(person1, person2);
    final Score score = personList.stream()
        .map(person -> person.getScores().stream().min(Comparator.comparing(Score::getScore)).get())
        .min(Comparator.comparing(Score::getScore))
        .get();
}

}

class Person {

private final String name;
private Collection<Score> scores;

public Person(final String name) {
    this.name = name;
}

public String getName() {
    return name;
}

public Collection<Score> getScores() {
    if (scores == null) {
        scores = new ArrayList<>();
    }
    return scores;
}
}

class Score {

private final Integer score;
private final Person person;

public Score(final Integer score, final Person person) {
    this.score = score;
    this.person = person;
}

public Person getPerson() {
    return person;
}

public Integer getScore() {
    return score;
}
}
  • Related