How to get the object that has the maximum value for multiple attributes using a stream?

MWB :

Say I have a bunch of villains. They are characterized by how good, bad or ugly they are.

static class Villain {
    String name;
    int good;
    int bad;
    int ugly;

    Villain(String name, int good, int bad, int ugly) {
        this.name = name;
        this.good = good;
        this.bad = bad;
        this.ugly = ugly;
    }
}

Okay, meet the gang:

List<Villain> villains = new ArrayList<>();
villains.add(new Villain("Bob", 2, 2, 1));
villains.add(new Villain("Charley", 2, 1, 2));
villains.add(new Villain("Dave", 2, 1, 1));
villains.add(new Villain("Andy", 2, 2, 2));
villains.add(new Villain("Eddy", 1, 2, 2));
villains.add(new Villain("Franz", 1, 2, 1));
villains.add(new Villain("Guy", 1, 1, 2));
villains.add(new Villain("Harry", 1, 1, 1));

What I want to do is, I want to figure out who is the best, worst and ugliest. With that I mean to figure out who is the best. In case of a tie, who is the worst. In case of a tie, who is the ugliest.

I have succeeded in doing so, with the code below.

List<Villain> bestVillains = villains
        .stream()
        .collect(groupingBy(v -> v.good, TreeMap::new, toList()))
        .lastEntry()
        .getValue()
        .stream()
        .collect(groupingBy(v -> v.bad, TreeMap::new, toList()))
        .lastEntry()
        .getValue()
        .stream()
        .collect(groupingBy(v -> v.ugly, TreeMap::new, toList()))
        .lastEntry()
        .getValue();

This, indeed, result in a List<Villain> with only one member: Andy. He truly is the best, worst and ugliest!

However, I have quite a bit of code repetition, collecting values, turning them into streams again, etc. Any suggestions on how te clean this up?

How is this being processed by the JVM. Sequentially or is there some magic going on underneath the hood?

Naman :

So the idea is that it first looks at which has the highest value for good, then (in case of a tie) which has the highest value for bad, then (if it is still not decisive) which has the highest value for 'ugly'

You are rather looking to sort using the following Comparator for Villians :

Comparator<Villain> villainComparator = Comparator.comparingInt(Villain::getGood)
    .thenComparingInt(Villain::getBad)
    .thenComparingInt(Villain::getUgly);

Villain result = villains.stream()
                         .max(villainComparator)
                         .orElse(null);

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=85378&siteId=1