如何使用流获取多个属性具有最大值的对象?
How to get the object that has the maximum value for multiple attributes using a stream?
说我有一帮小人。他们的特点是好、坏或丑。
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>
只有一个成员:Andy。他真的是最好的,最坏的,最丑的!
但是,我有相当多的代码重复、收集值、再次将它们转换为流等。关于如何清理它的任何建议?
JVM 是如何处理的。顺序地还是引擎盖下发生了一些魔法?
您可以使用嵌套分组
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());
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'
您更希望使用以下 Comparator
对 Villian
进行排序:
Comparator<Villain> villainComparator = Comparator.comparingInt(Villain::getGood)
.thenComparingInt(Villain::getBad)
.thenComparingInt(Villain::getUgly);
Villain result = villains.stream()
.max(villainComparator)
.orElse(null);
你需要的是一个比较器。您可以将其添加到您的信息流中。它看起来像这样:
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 个恶棍的列表 - 最差的一个。这里发生的是比较器只反向排序,然后你取第一个条目。
如果您只是担心代码重复,请尝试提取代码并重新使用它,例如:
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
class.
中添加了虚构的吸气剂
最里面的调用使用原始列表,其他调用使用这些函数的return。
这里作为专用函数
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);
但是,如果您也对 正确的工具或 模式 感兴趣,请参阅 @nullpointer 使用的方法比较器。
说我有一帮小人。他们的特点是好、坏或丑。
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>
只有一个成员:Andy。他真的是最好的,最坏的,最丑的!
但是,我有相当多的代码重复、收集值、再次将它们转换为流等。关于如何清理它的任何建议?
JVM 是如何处理的。顺序地还是引擎盖下发生了一些魔法?
您可以使用嵌套分组
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());
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'
您更希望使用以下 Comparator
对 Villian
进行排序:
Comparator<Villain> villainComparator = Comparator.comparingInt(Villain::getGood)
.thenComparingInt(Villain::getBad)
.thenComparingInt(Villain::getUgly);
Villain result = villains.stream()
.max(villainComparator)
.orElse(null);
你需要的是一个比较器。您可以将其添加到您的信息流中。它看起来像这样:
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 个恶棍的列表 - 最差的一个。这里发生的是比较器只反向排序,然后你取第一个条目。
如果您只是担心代码重复,请尝试提取代码并重新使用它,例如:
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
class.
最里面的调用使用原始列表,其他调用使用这些函数的return。
这里作为专用函数
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);
但是,如果您也对 正确的工具或 模式 感兴趣,请参阅 @nullpointer 使用的方法比较器。