【问题标题】:Using Stream methods in current stream method in Java 8在 Java 8 的当前流方法中使用流方法
【发布时间】:2017-04-14 18:32:42
【问题描述】:

我有一组整数,我想计算我的流包含的max() 整数的数量。 max() 方法来自 Stream API。

我想要这样的事情

int count = Arrays.stream(myIntArray)
            .filter(i -> i == max())
            .count();
System.out.printf("Count: %d", count);

我无法从我的 forEach() 方法中调用 max() 方法,因为 Streams 不是这样运行的 - 那么我该怎么做才能使它工作?

【问题讨论】:

  • max() 返回什么?
  • @m_callens max() 返回数组 Stream 中最大的 Integer。
  • 是调用属于流的max方法还是自己自定义的max方法?
  • 我正在尝试在 Stream API 中使用 max() 方法,抱歉。这还不够清楚。
  • @Aphex 你知道你不能在 lambda 中使用“count”,因为它必须是“final”才能被允许,并且当声明为“final”时你不能更改“count”的值"。

标签: java java-8 java-stream


【解决方案1】:

你不能做这样的事情,不是没有很多麻烦。写你想要的最简单的方法是两个阶段:

int max = Arrays.stream(array).max().getAsInt();
int count = (int) Arrays.stream(array).filter(i -> i == max).count();

如果你坚持一次性完成,我会写类似

int[] maxAndCount = Arrays.stream(array).collect(
    () -> new int[2], // first max, then count
    (maxAndCount, i) -> {
      if (i > maxAndCount[0] || maxAndCount[1] == 0) {
        maxAndCount[0] = i;
        maxAndCount[1] = 1;
      } else if (i == maxAndCount[0]) {
        maxAndCount[1]++;
      }
    },
    (maxAndCount1, maxAndCount2) -> {
      if (maxAndCount1[0] < maxAndCount2[0]) {
        maxAndCount1[0] = maxAndCount2[0];
        maxAndCount1[1] = maxAndCount2[1];
      } else if (maxAndCount1[0] == maxAndCount2[0]) {
        maxAndCount1[1] += maxAndCount2[1];
      }
    });
  int count = maxAndCount[1];

...但老实说,简单的两阶段版本很难被击败。 (坦率地说,我希望它表现得更好。)

【讨论】:

  • @JacobG。读取Arrays.stream(int[])的返回类型
  • 使用getAsInt()意味着空数组将失败并返回NoSuchElementException,而不是导致最大计数为0(没有最大元素,因此它们的计数为0) .由于 OP 只对计数感兴趣,而不是最大值本身,因此使用 orElse(0) 会更好。
  • 好奇: 为什么你认为两次迭代数组比在一次迭代中收集maxcount 更快?如果您的答案是“因为int[2] 数组的索引访问”,那么我会说使用类来解决这个问题。另一个问题请参见my answer
  • 不确定您所说的“没有要处理的堆变量”是什么意思,因为您的代码在调用过滤器 lambda 表达式时使用了堆。调用filter() 谓词或collect() 累加器大致相同,但双流意味着您有两次向下游发送迭代值的开销,即使用堆。 --- 无论如何,有点争议,因为如果你真的想要 fast,你就不会为此使用流,只是一个常规的 for 循环,所以我同意两线是更好/更简单/更容易理解,但性能不是原因。
  • 赞成,但我仍然认为你应该使用orElse(0)
【解决方案2】:

如果您想为此使用流,则必须使用保存状态的对象 - 您可以为此任务使用自定义收集器:

public static void main(String[] args) {
    final int[] arr = {1, 2, 3, 4, 5, 1, 2, 3, 5};
    class MaxCollector {

        int max = Integer.MIN_VALUE;
        int count = 0;

        public void accept(int value) {
            if (max < value) {
                max = value;
                count = 1;
            } else if (max == value) {
                count++;
            }
        }

        public void combine(MaxCollector other) {
            if (max == other.max) {
                count += other.count;
            } else if (max < other.max) {
                max = other.max;
                count = other.count;
            }
        }
    }
    final MaxCollector m = Arrays.stream(arr).collect(
            MaxCollector::new, MaxCollector::accept, MaxCollector::combine);
    System.out.println(m.max + " : " + m.count);
}

【讨论】:

    【解决方案3】:

    您也可以使用以下流代码(带有内联 cmets),它给出了出现次数(最大次数):

    int maxValueCount = Arrays.stream(myIntArray).
          collect(Collectors.groupingBy(Function.identity(), 
          Collectors.counting())).//group by numbers and counts first
          entrySet().stream().//get Elements from group Map
           max((entry1, entry2) -> 
               (int)(entry1.getValue() - entry2.getValue())).//find max number in map
           get().getValue();//get the count of maximum number
    

    【讨论】:

      【解决方案4】:

      您可以先获取最大值,然后再进行流式传输。

      int max = Arrays.stream(myIntArray).max().getAsInt(); 
      
      int count = Arrays.stream(myIntArray)
                  .filter(i -> i == max)
                  .count();
      System.out.printf("Count: %d", count);
      

      【讨论】:

        【解决方案5】:

        只需使用 Collections 类中的频率方法。它的存在正是为了这个目的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-26
          • 2014-07-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多