【问题标题】:Java Stream sum() short circuiting [duplicate]Java Stream sum()短路[重复]
【发布时间】:2018-12-06 20:31:56
【问题描述】:

我在做项目的时候写了这行代码,基本上是根据子节点的数量来决定是否合并当前节点。

int succNodes = Arrays.stream(children).mapToInt(PRQuadNode::count).sum();
if (succNodes <= bucketingParam) { /* do something */ }

问题在于succNodes 通常会明显大于bucketingParam。如果我已经找到了足够大的数目,就没有必要继续数了。如果我知道我将无法通过检查 succNodes

注意:在这种情况下,children 的大小始终为 4。

注2:PRQuadNode::count是递归方法,不是尾递归。

【问题讨论】:

  • 根据 SO 政策,您可以提出家庭作业问题,前提是您真诚地努力解决问题,并且您的学校没有禁止发布此问题的政策。所以你应该可以发布你所拥有的(仅供参考)。
  • 实际上最好在没有流的情况下执行此操作。

标签: java java-stream


【解决方案1】:

其实Java 9自带takeWhile方法,是流的短路操作,返回匹配给定谓词的元素的最长前缀

因为谓词取决于前面元素的总和,所以必须使用包装器来存储中间结果。在下面的示例中,我使用了AtomicInteger 类:

AtomicInteger sum = new AtomicInteger();
Arrays.asList(2, 3, 5, 7, 11, 13, 17).stream()
    .takeWhile(i -> sum.addAndGet(i) < 15)
    .forEach(System.out::println);

返回:

2
3
5

【讨论】:

    【解决方案2】:

    您不能仅使用流来短路流管道。

    一种解决方法(使用副作用)是:

    int[] c = new int[1];
    boolean r = Arrays.stream(children).noneMatch(e -> (c[0] = c[0] + e.count()) > bucketingParam);
    if (r) { /* do something */ }
    

    这完成了任务,但不幸的是,它不是线程安全的(怀疑你是否会并行运行它,因为你的源代码总是有 4 个元素)。

    命令式方法是:

    int succNodes = 0;
    boolean result = true;
    for (PRQuadNode p : children) {
        if (succNodes > bucketingParam) {
             result = false;
             break;
        }
        succNodes += p.count();
    }
    
    if (result) { /* do something */ }
    

    【讨论】:

      【解决方案3】:

      stream 无法做到这一点。但是,如果它大于bucketingParam,您已经可以过滤掉。 如果其中任何一个已经大于bucketingParam,那么继续下去是没有意义的。

      if (Arrays.stream(children).mapToInt(PRQuadNode::count)
                                 .noneMatch(x -> x > bucketingParam)) {
          int succNodes = Arrays.stream(children).mapToInt(PRQuadNode::count).sum();
      }
      

      【讨论】:

        猜你喜欢
        • 2017-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-21
        • 1970-01-01
        • 2012-11-05
        • 2015-12-06
        • 2020-01-06
        相关资源
        最近更新 更多