100

我需要弄清楚IterableJava中元素的数量。我知道我可以这样做:

Iterable values = ...
it = values.iterator();
while (it.hasNext()) {
  it.next();
  sum++;
}

我也可以这样做,因为我不再需要 Iterable 中的对象:

it = values.iterator();
while (it.hasNext()) {
  it.remove();
  sum++;
}

小规模基准测试没有显示出太大的性能差异,对此问题有任何评论或其他想法吗?

4

10 回答 10

135

TL;DR:使用Iterables.size(Iterable)伟大的Guava库的实用方法。

在您的两个代码片段中,您应该使用第一个,因为第二个将从中删除所有元素values,因此之后它是空的。像大小这样的简单查询更改数据结构是非常出乎意料的。

对于性能,这取决于您的数据结构。例如,如果它实际上是一个ArrayList,从头开始删除元素(你的第二种方法正在做的)非常慢(计算大小变成 O(n*n) 而不是 O(n) 应该是)。

一般来说,如果有可能values实际上是 aCollection而不仅仅是 a Iterable,请检查并调用size()以防万一:

if (values instanceof Collection<?>) {
  return ((Collection<?>)values).size();
}
// use Iterator here...

调用 tosize()通常比计算元素的数量要快得多,而这个技巧正是GuavaIterables.size(Iterable)为您所做的。

于 2012-07-22T09:12:29.017 回答
46

如果您使用的是 java 8,则可以使用:

Iterable values = ...
long size = values.spliterator().getExactSizeIfKnown();

只有当可迭代源具有确定的大小时,它才会起作用。大多数集合拆分器都会,但如果它来自一个HashSetResultSet例如,你可能会遇到问题。

您可以在此处查看 javadoc。

如果 Java 8 不是一个选项,或者如果您不知道可迭代的来源,您可以使用与番石榴相同的方法:

  if (iterable instanceof Collection) {
        return ((Collection<?>) iterable).size();
    } else {
        int count = 0;
        Iterator iterator = iterable.iterator();
        while(iterator.hasNext()) {
            iterator.next();
            count++;
        }
        return count;
    }
于 2016-02-26T08:48:13.590 回答
19

这可能有点晚了,但可能会对某人有所帮助。Iterable我在我的代码库中遇到了类似的问题,解决方案是在for each不明确调用的情况下使用values.iterator();.

int size = 0;
for(T value : values) {
   size++;
}
于 2013-11-01T12:39:31.777 回答
7

您可以将您的可迭代对象转换为列表,然后在其上使用 .size() 。

Lists.newArrayList(iterable).size();

为了清楚起见,上述方法将需要以下导入:

import com.google.common.collect.Lists;
于 2016-01-13T13:31:25.547 回答
6

严格来说,Iterable 没有大小。把数据结构想象成一个循环。

并考虑以下 Iterable 实例,没有大小:

    new Iterable(){

        @Override public Iterator iterator() {
            return new Iterator(){

                @Override
                public boolean hasNext() {
                    return isExternalSystemAvailble();
                }

                @Override
                public Object next() {
                    return fetchDataFromExternalSystem();
                }};
        }};
于 2012-07-22T09:33:15.677 回答
3

java 8及以上

StreamSupport.stream(data.spliterator(), false).count();
于 2019-09-03T12:08:20.803 回答
2

我会选择保证it.next()实现的简单原因next(),而remove()这是一个可选操作。

E next()

返回迭代中的下一个元素。

void remove()

从基础集合中移除迭代器返回的最后一个元素(可选操作)

于 2012-07-22T09:12:16.590 回答
0

至于我,这些只是不同的方法。第一个使您正在迭代的对象保持不变,而第二个则使其为空。问题是你想做什么。删除的复杂性取决于可迭代对象的实现。如果您正在使用 Collections - 只需获得 Kazekage Gaara 建议的大小 - 它通常是最好的方法性能明智。

于 2012-07-22T09:15:02.790 回答
-2

你为什么不简单地使用你的size()方法Collection来获取元素的数量?

Iterator只是为了迭代,没有别的。

于 2012-07-22T09:10:00.863 回答
-4

我们可以简单地对 ArrayList 中的可迭代对象进行类型转换并获取其大小,而不是使用循环和计算每个元素或使用第三方库。

((ArrayList) iterable).size();
于 2018-03-13T07:01:20.893 回答