【问题标题】:Is there a more elegant way to select between max or min method from a stream?有没有更优雅的方法来从流中选择 max 或 min 方法?
【发布时间】:2015-11-23 17:15:02
【问题描述】:

我想根据某些条件从列表中获取最小或最大项目。 下面的 sn-p 总结了我在做什么:

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

它有效,但非常冗长。本质上,我想在流中选择 minma​​x 方法。有没有更好的方法来做到这一点?

【问题讨论】:

  • 你的意思是d1.age() - d2.age()

标签: java java-8 java-stream


【解决方案1】:

这是另一种方式:

Comparator<Person> comp = Comparator.comparingInt(Person::age);
BinaryOperator<Person> op 
    = condition ? BinaryOperator.minBy(comp) : BinaryOperator.maxBy(comp);

Optional<Person> target = list.stream().reduce(op);

【讨论】:

    【解决方案2】:

    我建议使您的意图最清晰的方法是:

    Comparator<Person> ageComparator = Comparator.comparingInt(Person::age);
    Optional<Person> target = condition ? 
        list.stream().min(ageComparator) : list.stream().max(ageComparator);
    

    【讨论】:

    • 我喜欢所有建议的“聪明”替代方案,但我认为这就是我实际要做的方式。
    【解决方案3】:

    你可以这样做:

    Comparator<Person> c = Comparator.comparingInt(Person::age);
    Optional<Person> target = detailedList.stream().min(condition ? c : c.reversed());
    

    它更短,但我个人认为将minreversed 结合起来找到最大值有点小题大做。我会坚持原来的。

    【讨论】:

      【解决方案4】:

      另一种解决方案是使用相同的收集步骤同时计算最小值和最大值。为此,我们可以从 IntSummaryStatistics 类中启发自己,并构造一个 ObjectSummaryStatistics 来保存最小值和最大值。

      对于您的特定用例而言,此解决方案可能太多了。仅当您发现自己经常这样做时,它可能会很方便。

      最小值和最大值初始化为null,并在每次接受元素或进行组合时更新。我使用Optionals 作为返回值,以与常见的minmax 操作的API 返回值一致。

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

      旁注:您的问题中的 Comparator 不是可传递的,因此它不会按原样工作

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-10
        • 2012-11-15
        • 1970-01-01
        • 1970-01-01
        • 2023-03-07
        • 1970-01-01
        • 2020-01-08
        • 2011-04-05
        相关资源
        最近更新 更多