获得迭代器的数量/长度/大小的最佳方式是什么?

问题描述:

是否有一种“计算上”的快速方法来获得迭代器的计数?获得迭代器的数量/长度/大小的最佳方式是什么?

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

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

+2

迭代器不一定对应于具有“count”的东西... – 2012-03-15 13:01:05

+0

迭代器是它们是什么;迭代到集合中的下一个对象(它可以是set,array等任何东西)为什么当他们不关心他们想要迭代的内容时,他们需要告诉大小? '为访问提供独立于实现的方法,其中用户不需要知道底层实现是某种形式的数组还是链接列表,并且允许用户在没有明确索引的情况下浏览集合。 /penguin.ewu.edu/~trolfe/LinkedSort/Iterator.html – ecle 2012-03-15 13:01:42

如果你拿到的迭代器那么这是你必须做的 - 它不知道它有多少项目就剩到迭代,所以你不能查询它的结果。

但是,许多迭代器来自集合,您可以经常查询它们的大小。如果它是一个用户创建的类,您将获得迭代器,您可以在该类上提供size()方法。

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

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

解决方案是更改您的应用程序,使其不需要计数或通过其他方式获取计数。 (例如,通过一个Collection而非Iterator ...)

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

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

如果你有机会访问底层集合,你就可以打电话coll.size() ......

编辑 确定你已经修改了...

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

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

而是获得迭代器的尺寸,并通过索引0迭代到规定大小,最好是通过该方法的迭代器的下()进行迭代。

+0

如果我们没有'a',但只有'i',该怎么办? – Tvde1 2017-09-25 08:47:52

如果你拥有的只是迭代器,那么不,没有“更好”的方法。如果迭代器来自一个集合,那么可以按照大小进行设置。

请记住,迭代器就是为穿越不同值的界面,你会很好得如下代码

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"); 
     } 
    }; 

使用Guava library

int size = Iterators.size(iterator); 

内部它只是遍历所有元素,所以它只是为了方便。

另一种选择是将Iterable转换为List

int count = Lists.newArrayList(some_iterator).size(); 
+1

它有多少效率? – LoveToCode 2016-04-27 12:55:48

+2

@LoveToCode比原始问题上的例子效率低 – Winter 2016-12-20 17:44:41

+2

当然,创建一个包含所有元素的新对象比迭代和丢弃要慢。恕我直言,这个解决方案是一个提高代码可读性的单线程。我使用它很多元素(高达1000)或速度不是问题的集合。 – tashuhka 2016-12-21 10:05:23

您将始终需要迭代。然而,你可以使用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();