【问题标题】:Efficiency of collection.stream().skip().findFirst()collection.stream().skip().findFirst() 的效率
【发布时间】:2016-08-05 09:54:00
【问题描述】:

假设set 是带有n 元素的HashSet,而k 是介于0(包括)和n(不包括)之间的一些int

有人可以简单地解释一下,当你这样做时实际发生了什么?

set.stream().skip(k).findFirst();

具体来说,它的时间复杂度是多少?将spliterator() 添加到Collection 接口是否意味着我们现在可以比Java 7 更快地访问集合的“随机”元素?

【问题讨论】:

  • 一般来说不,不,也不是HashSetHashSet.spliterator() 没有 ORDERED 属性,因此您可能会在此处得到未定义的行为。
  • @LouisWasserman 谢谢,我没想到,只是想确认一下。
  • 您可能会注意到Spliterator 接口本身没有skip 方法或任何其他将指针移动到当前元素的方法。因此,没有办法在此之上实现“更快地访问集合的‘随机’元素”。
  • @Holger 是的,这是一个非常愚蠢的问题。我需要好好研究一下,因为我仍然不完全确定分裂器是什么。
  • 我不认为这是一个愚蠢的问题。通过查看 Stream API 本身,通常不清楚内部优化的实际潜力在哪里,在哪里没有。某些部分故意未指定,并且在当前实现中令人惊讶地忽略了一些明显的潜力。对很多开发者来说,它似乎有一种神秘的气氛……

标签: java collections java-8 java-stream


【解决方案1】:

当前的实现具有 O(k) 复杂度,更不用说等价于以下内容:

Iterator<?> it = set.iterator();
for(int i=0; i<k && it.hasNext(); i++) it.next();
return it.hasNext() ? Optional.of(it.next()) : Optional.empty();

当前的实现从不考虑顺序流的ORDERED 特征。 @the8472 答案中引用的代码仅适用于并行流。在并行情况下,摊销复杂度大约为 O(k/n),其中 n 是处理器的数量。

【讨论】:

    【解决方案2】:

    正如 louis 提到的,skip 在无序流上实际上没有意义,事实上,它目前 (jdk 1.8) 以以下方法在某些情况下优化跳过的方式实现:

            Spliterator<T> unorderedSkipLimitSpliterator(Spliterator<T> s,
                                                         long skip, long limit, long sizeIfKnown) {
                if (skip <= sizeIfKnown) {
                    // Use just the limit if the number of elements
                    // to skip is <= the known pipeline size
                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
                    skip = 0;
                }
                return new StreamSpliterators.UnorderedSliceSpliterator.OfRef<>(s, skip, limit);
            }
    

    这是有效的,因为它相当于简单地以不同的顺序遍历源集合。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-20
      • 1970-01-01
      • 1970-01-01
      • 2016-01-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多