获取Java中Iterable的大小

时间:2012-07-22 09:06:25

标签: java iterable

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

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

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

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

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

10 个答案:

答案 0 :(得分:103)

TL; DR:使用优质Iterables.size(Iterable)库的实用方法Guava

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

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

一般情况下,如果values实际上只有Collection而不仅仅是Iterable,请检查此项并在以下情况下致电size()

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

size()的调用通常比计算元素数量要快得多,这个技巧正是Iterables.size(Iterable) Guava为你做的。

答案 1 :(得分:34)

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

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

仅当可迭代源具有确定的大小时才会起作用。大多数收藏的Spliterator都会,但如果它来自HashSetResultSet,则可能会遇到问题。

您可以查看javadoc here.

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

  if (iterable instanceof Collection) {
        return ((Collection<?>) iterable).size();
    } else {
        int count = 0;
        Iterator iterator = iterable.iterator();
        while(iterator.hasNext()) {
            iterator.next();
            count++;
        }
        return count;
    }

答案 2 :(得分:13)

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

int size = 0;
for(T value : values) {
   size++;
}

答案 3 :(得分:6)

严格来说,Iterable没有大小。认为数据结构就像一个循环。

考虑关注Iterable实例,没有大小:

    new Iterable(){

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

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

                @Override
                public Object next() {
                    return fetchDataFromExternalSystem();
                }};
        }};

答案 4 :(得分:5)

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

Lists.newArrayList(iterable).size();

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

import com.google.common.collect.Lists;

答案 5 :(得分:2)

我会选择it.next(),原因很简单,next()可以保证实施,而remove()是可选操作。

E next()
     

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

void remove()
     

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

答案 6 :(得分:0)

至于我,这些只是不同的方法。第一个离开你正在迭代的对象,而秒则将它留空。 问题是你想做什么。 删除的复杂性基于可迭代对象的实现。 如果你正在使用收藏 - 只需获得像Kazekage Gaara所提出的那样大小 - 它通常是性能最好的方法。

答案 7 :(得分:0)

java 8及更高版本

StreamSupport.stream(data.spliterator(), false).count();

答案 8 :(得分:-2)

为什么不在size()上使用Collection方法获取元素数量?

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

答案 9 :(得分:-3)

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

new Row(
    children: <Widget>[
      new Flexible(child: new Text("Babe"), flex: 1,),
      new Flexible(child: new Text("I miss you"), flex: 1,)
    ],
  )