获取迭代器的计数/长度/大小的最佳方法是什么?


96

是否有一种“计算”快速的方法来获取迭代器的数量?

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

...似乎浪费了CPU周期。


2
迭代器不一定对应于带有“计数”的对象...
奥利弗·查尔斯沃思

迭代器就是它们。迭代到集合的下一个对象(可以是集合,数组等),当他们不在乎要迭代的内容时,为什么要告诉大小?to provide an implementation-independent method for access, in which the user does not need to know whether the underlying implementation is some form of array or of linked list, and allows the user go through the collection without explicit indexing. penguin.ewu.edu/~trolfe/LinkedSort/Iterator.html
ecle

Answers:


67

如果您只有迭代器,那么这就是您要做的-它不知道要迭代剩下多少个项目,因此您无法查询该结果。有一些实用程序方法似乎可以做到这一点(例如Iterators.size()在Guava中),但是在它们的下面仅执行大致相同的操作。

但是,许多迭代器来自集合,您通常可以查询集合的大小。如果它是用户制作的类,那么您将为其提供迭代器,则可以在该类上提供size()方法。

简而言之,在只有迭代器的情况下,没有更好的方法了,但是比起没有访问权的更多途径,您可以直接从底层集合或对象中获取大小。


注意Iterators.size(...)(在下面的其他注释中以及在java-doc中提到的)副作用:“返回迭代器中剩余的元素数。迭代器将被耗尽:其hasNext()方法将返回false。” 这意味着您以后将无法再使用Iterator。Lists.newArrayList(some_iterator);可能会有所帮助。
MichaelCkr

91

使用番石榴库

int size = Iterators.size(iterator);

在内部,它只是遍历所有元素,因此仅是为了方便。


8
这非常优雅。请记住,您正在消耗迭代器(即迭代器之后将为空)
lolski '18年

1
这不是“快速计算”,这是一种方便的方法,具有消耗迭代器的不良副作用。
扎克

您能解释一下这是如何工作的吗?@Andrejs List <Tuple2 <String,Integer >> wordCountsWithGroupByKey = wordsPairRdd.groupByKey().mapValues(intIterable-> Iterables.size(intIterable))。collect(); System.out.println(“ wordCountsWithGroupByKey:” + wordCountsWithGroupByKey); “ Iterables.size(intIterable)?
Aditya Verma

15

当您到达迭代器的末尾时,您的代码将为您提供一个例外。您可以这样做:

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

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

编辑 好,你已经修改了...


这有多有效?如果迭代器像一百万个值怎么办?
Micro Micro

4
@Micro从技术上讲,迭代器可能是无限的-在这种情况下,循环将永远继续下去。
assylias 18-10-16

11

您将始终需要迭代。但是,您可以使用Java 8、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此调用的标志来并行化计数操作:

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

8

使用Guava库,另一种选择是将转换IterableList

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

如果您还需要在获取迭代器的大小后访问其元素,请使用此方法。通过使用,Iterators.size()您不再可以访问迭代的元素。


2
@LoveToCode比原始问题的示例效率低

2
当然,创建具有所有元素的新对象比仅进行迭代和丢弃要慢。恕我直言,此解决方案是单行代码,可提高代码的可读性。当元素很少(最多1000个)或速度不是问题时,我经常使用它。
tashuhka

7

如果您只有迭代器,那么没有,没有“更好”的方法。如果迭代器来自集合,则可以选择大小。

请记住,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");
        }
    }; 

4

如果您拥有的只是迭代器,则没有更有效的方法。而且,如果迭代器只能使用一次,那么在获取迭代器的内容之前先获得计数是有问题的。

解决方案是更改您的应用程序以使其不需要计数,或者通过其他方式获得计数。(例如,传递a Collection而不是Iterator...)


0

对于Java 8,您可以使用

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

-5

迭代器对象包含与集合包含的元素数量相同的元素。

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

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


如果我们没有a,怎么办i呢?
Tvde1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.