我希望根据某些条件从列表中获取最小或最大项目。 下面的摘录总结了我的工作:
Optional<Person> target;
if(condition){
target = detailedList.stream().min((d1, d2) -> d1.age() + d2.age());
} else {
target = detailedList.stream().max((d1, d2) -> d1.age() + d2.age());
}
它有效,但非常冗长。本质上,我想在流中选择方法 min 或 max 。有更好的方法吗?
答案 0 :(得分:8)
这是另一种方式:
Comparator<Person> comp = Comparator.comparingInt(Person::age);
BinaryOperator<Person> op
= condition ? BinaryOperator.minBy(comp) : BinaryOperator.maxBy(comp);
Optional<Person> target = list.stream().reduce(op);
答案 1 :(得分:4)
我建议让你的意图最清晰的方法是:
Comparator<Person> ageComparator = Comparator.comparingInt(Person::age);
Optional<Person> target = condition ?
list.stream().min(ageComparator) : list.stream().max(ageComparator);
答案 2 :(得分:2)
你可以这样做:
Comparator<Person> c = Comparator.comparingInt(Person::age);
Optional<Person> target = detailedList.stream().min(condition ? c : c.reversed());
它更短,但我个人认为将min
与reversed
结合起来找到最大值有点像黑客。我会坚持原来的。
答案 3 :(得分:1)
另一种解决方案是使用相同的收集步骤计算最小值和最大值。为此,我们可以从IntSummaryStatistics
类激发自己,并构建一个ObjectSummaryStatistics
来保存最小值和最大值。
对于您的特定用例,此解决方案可能太多了。只有当你发现自己做了很多事情时,这可能会很方便。
min和max初始化为null
,并在每次接受元素或进行合并时更新。我使用Optional
作为返回值,以便与API为常见的min
和max
操作返回的内容保持一致。
public class ObjectSummaryStatistics<T> implements Consumer<T> {
private long count;
private T min;
private T max;
private Comparator<T> comparator;
public ObjectSummaryStatistics(Comparator<T> comparator) {
this.comparator = Objects.requireNonNull(comparator, "A comparator must be set");
}
@Override
public void accept(T t) {
min = count == 0 ? t : min(min, t);
max = count == 0 ? t : max(max, t);
count++;
}
public void combine(ObjectSummaryStatistics<T> other) {
if (other.comparator != comparator) {
throw new IllegalArgumentException("Can't combine with a summary statistics having a different comparator");
}
if (count == 0) {
min = other.min;
max = other.max;
} else if (other.count > 0) {
min = min(min, other.min);
max = max(max, other.max);
}
count += other.count;
}
public Optional<T> getMin() {
return Optional.ofNullable(min);
}
public Optional<T> getMax() {
return Optional.ofNullable(max);
}
public long getCount() {
return count;
}
private T min(T t1, T t2) {
return comparator.compare(t1, t2) <= 0 ? t1 : t2;
}
private T max(T t1, T t2) {
return comparator.compare(t1, t2) >= 0 ? t1 : t2;
}
}
然后你可以构建一个收集到这个类的Collector
:
public static <T> Collector<T, ?, ObjectSummaryStatistics<T>> summarizing(Comparator<T> comparator) {
return Collector.of(
() -> new ObjectSummaryStatistics<T>(comparator),
ObjectSummaryStatistics::accept,
(s1, s2) -> { s1.combine(s2); return s1; }
);
}
最后,您的代码变为:
ObjectSummaryStatistics<Person> s = detailedList.stream().collect(summarizing((d1, d2) -> d1.age() + d2.age()));
System.out.println(s.getMin());
System.out.println(s.getMax());
旁注:你问题中的比较者不具有传递性,因此无法正常使用