如何获得具有对使用流多个属性最大值的对象?

问题描述 投票:3回答:4

说我有一帮坏人。他们是由他们有多么好,坏或丑陋的表征。

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

好吧,满足刚:

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));

我想要做的是,我想弄清楚谁是最好的,最差和最丑陋的。随着我的意思是要弄清楚谁是最好的。在平局的情况下,谁是最糟糕的。在平局的情况下,谁是最丑陋的。

我已经做得很成功,与下面的代码。

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();

确实,这导致只有一个成员的List<Villain>:安迪。他真的是最好的,最差和最丑陋!

不过,我有相当多的代码重复,收藏价值,再次把它们变成流等就如何TE打扫一下有什么建议?

这是如何由JVM处理。顺序或者是有一些神奇的事情引擎盖下面?

java java-stream dry
4个回答
5
投票

这样的想法是,它首先看它有良好的话(在平局的情况下),它有不好的话(如果它仍然不是决定性的)的最高值,这对于价值最高的“丑陋的最高值“

您正在寻找,而使用以下ComparatorVillians排序:

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

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

2
投票

您可以使用嵌套groupingBy

TreeMap<Integer, TreeMap<Integer, TreeMap<Integer, List<Villain>>>> collect = 
    villains.stream()
        .collect(groupingBy(v -> v.good, TreeMap::new,
                     groupingBy(v -> v.bad, TreeMap::new,
                         groupingBy(v -> v.ugly, TreeMap::new, mapping(o -> o, toList())))));

然后打印:

System.out.println(collect.lastEntry().getValue()
                      .lastEntry().getValue()
                          .lastEntry().getValue());

2
投票

你需要的是一个比较。您可以添加到您的流。它看起来是这样的:

List<Villain> bestVillains = villains.stream()
        .sorted((o1, o2) -> {
            if(o2.good == o1.good){
                if(o2.bad == o1.bad){
                    return o2.ugly - o1.ugly;
                }else{
                    return o2.bad - o1.bad;
                }
            }else{
                return o2.good - o1.good;
            }
        })
        .limit(1)
        .collect(Collectors.toList());

这将产生1小人的名单 - 最差的一群。这里发生的是比较唯一的种种反向,然后你把第一个条目。


1
投票

如果你只是关心代码重复,尝试提取的代码,并重新使用它,例如:

final BiFunction<List<Villain>, Function<Villain, Object>, List<Villain>> func = (listVillians, villianAttribute) -> listVillians
    .stream()
    .collect(groupingBy(villianAttribute, TreeMap::new, toList()))
    .lastEntry()
    .getValue();

并使用它像这样:

List<Villain> bestVillainsMK2 = func.apply(func.apply(func.apply(villains, Villain::getGood), Villain::getBad), Villain::getUgly);

注:我添加了虚构的干将到Villain类。

最内侧的呼叫使用原来的名单中,其他人使用这些功能的回归。

这里作为专用功能

private static List<Villain> func2(List<Villain> listVillians, Function<Villain, Object> villianAttribute) {
    return listVillians.stream()
      .collect(groupingBy(villianAttribute, TreeMap::new, toList()))
      .lastEntry()
      .getValue();
}

使用几乎是相同的

List<Villain> bestVillainsMK3 = func2(func2(func2(villains, Villain::getGood), Villain::getBad), Villain::getUgly);

但是,如果你也有兴趣在正确的工具或模式对于您的情况,使用比较看@nullpointers方法。

© www.soinside.com 2019 - 2024. All rights reserved.