What is the best way to get the count/length/size of an iterator?

有没有一种“计算上的”快速方法来获得迭代器的计数?

int i = 0;
for ( ; some_iterator.hasNext() ; ++i ) some_iterator.next();

看起来像是在浪费 CPU 周期。

225311 次浏览

There is no more efficient way, if all you have is the iterator. And if the iterator can only be used once, then getting the count before you get the iterator's contents is ... problematic.

解决方案是要么更改应用程序,使其不需要计数,要么通过其他方法获取计数。(例如,传递一个 Collection而不是 Iterator...)

如果你已经得到了迭代器,那么这就是你必须要做的事情-它不是 知道有多少项目它还有多少次迭代,所以你不能查询它的结果。有一些实用程序方法可以让 seem高效地完成这项工作(比如番石榴中的 Iterators.size()) ,但是在底层,它们只是使用迭代器,并在运行时进行计数,这与您的示例中的情况相同。

但是,许多迭代器来自集合,您通常可以查询它们的大小。如果要为用户创建的类获取迭代器,那么可以在该类上提供 size ()方法。

简而言之,在使用 only迭代器的情况下,没有更好的方法,但通常情况下,您可以访问底层集合或对象,从中可以直接获取大小。

当你到达迭代器的末尾时,你的代码会给你一个异常。你可以这样做:

int i = 0;
while(iterator.hasNext()) {
i++;
iterator.next();
}

如果您能够访问基础集合,则可以调用 coll.size()..。

剪辑 好的,你已经修改了..。

Iterator 对象包含的元素数与集合包含的元素数相同。

List<E> a =...;
Iterator<E> i = a.iterator();
int size = a.size();//Because iterators size is equal to list a's size.

但是,与其得到迭代器的大小并通过索引0迭代到该大小,不如通过迭代器的方法 下一个()进行迭代。

如果您只有迭代器,那么不,没有“更好”的方法。如果迭代器来自一个集合,那么可以用它来表示大小。

请记住,Iterator 只是一个跨越不同价值观的接口,您很可能拥有这样的代码

    new Iterator<Long>() {
final Random r = new Random();
@Override
public boolean hasNext() {
return true;
}


@Override
public Long next() {
return r.nextLong();
}


@Override
public void remove() {
throw new IllegalArgumentException("Not implemented");
}
};

或者

    new Iterator<BigInteger>() {
BigInteger next = BigInteger.ZERO;


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


@Override
public BigInteger next() {
BigInteger current = next;
next = next.add(BigInteger.ONE);
return current;
}


@Override
public void remove() {
throw new IllegalArgumentException("Not implemented");
}
};

使用 番石榴图书馆:

int size = Iterators.size(iterator);

Internally it just iterates over all elements so its just for convenience.

使用 Guava library,另一种选择是将 Iterable转换为 List

List list = Lists.newArrayList(some_iterator);
int count = list.size();

如果在获得迭代器的大小之后还需要访问迭代器的元素,则使用此方法。通过使用 Iterators.size(),您不再能够访问迭代的元素。

您总是需要迭代,但是您可以使用 Java8,9来进行计数,而不需要显式地进行循环:

Iterable<Integer> newIterable = () -> iter;
long count = StreamSupport.stream(newIterable.spliterator(), false).count();

这里有一个测试:

public static void main(String[] args) throws IOException {
Iterator<Integer> iter = Arrays.asList(1, 2, 3, 4, 5).iterator();
Iterable<Integer> newIterable = () -> iter;
long count = StreamSupport.stream(newIterable.spliterator(), false).count();
System.out.println(count);
}

这张照片:

5

有趣的是,你可以通过改变这个调用的 parallel标志来并行执行 count 操作:

long count = StreamSupport.stream(newIterable.spliterator(), *true*).count();

你可以使用 爪哇8,

public static int getIteratorSize(Iterator iterator){
AtomicInteger count = new AtomicInteger(0);
iterator.forEachRemaining(element -> {
count.incrementAndGet();
});
return count.get();
}

获取 Iterable 的大小

Iterable<Users> users = usersRepository.findUsersByLocation("IND");

现在断言 Type Iterable 的用户大小

assertEquals(2, ((Collection<Users>)users).size());