2012-03-15 2 views
61

イテレータの数を取得するための「計算上」の素早い方法はありますか?イテレータのカウント/長さ/サイズを取得する最良の方法は何ですか?

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

... CPUサイクルの浪費のようです。

+2

イテレータは必ずしも "カウント"を持つものには対応していません... –

+0

イテレータは、コレクションの次のオブジェクトに反復する(set、arrayなどのようなものになり得る)なぜ反復しようとしているか気にしないときにサイズを伝える必要があるのはなぜですか? '実装に依存しないアクセスのためのメソッドを提供します。このメソッドでは、基本となる実装が何らかの配列やリンクされたリストであるかどうかを知る必要はなく、明示的なインデックスなしでコレクションを通過できます。 /penguin.ewu.edu/~trolfe/LinkedSort/Iterator.html – ecle

答えて

52

(例えば、CollectionではなくIteratorを...渡します)繰り返すので、その結果を問い合わせることはできません。

しかし、多くのイテレータはコレクションから作成されます。コレクションの多くは、そのサイズを問い合わせることができます。また、イテレータを取得しているユーザ作成クラスの場合は、そのクラスに対してsize()メソッドを提供することができます。

にはイテレータがありますが、より良い方法はありませんが、サイズを直接取得できる基になるコレクションまたはオブジェクトにアクセスすることはずっと多いでしょう。

4

あなたが持つすべてがイテレータであれば、効率的な方法はありません。イテレータを一度しか使用できない場合は、イテレータの内容を取得する前にカウントを取得することは問題ありません。

解決方法は、カウントを必要としないようにアプリケーションを変更するか、他の手段でカウントを取得することです。それははそれが左の持っているどのように多くのアイテムを知らない - あなただけのイテレータを持っていれば、その後それはあなたが行う必要があるでしょう何

7

イテレータの最後に到達すると、コードによって例外が発生します。あなたは何ができる:

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

あなたが基になるコレクションへのアクセスを持っていた場合、あなたはcoll.size()を呼び出すことができるだろう...

EDITあなたが改正されているOK ...

-3

イテレータオブジェクトには、コレクションに含まれているものと同じ数の要素が含まれます。

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

5

あなたが持っているものがすべてイテレータであれば、いいえ、「良い」方法はありません。イテレータがコレクションから来ている場合は、サイズのためにそれを行うことができます。

イテレータは、個別の値を横断するためだけのインタフェースであることに注意してください、あなたは非常によくGuava libraryを使用するように、この

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

として、コードを持っているでしょう:

int size = Iterators.size(iterator); 

内部的には、すべての要素を繰り返し処理するため、便宜上のものです。

4

もう1つの方法は、IterableListに変換することです。

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

どれくらい効率化しますか? – LoveToCode

+2

@LoveToCode元の質問の例よりも効率が悪い – Winter

+2

確かに、すべての要素で新しいオブジェクトを作成するのは、繰り返しや破棄よりも遅いです。 IMHO、このソリューションは、コードの可読性を向上させる1つのライナーです。要素数が少ない(1000まで)コレクションや、速度が問題にならないコレクションには、これを多く使用しています。 – tashuhka

2

いつも繰り返す必要があります。しかし、あなたは明示的にループなしでカウントを行うためにJava 8、9使用することができます。

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 

興味深いあなたが並列化することができます。ここ

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

はテストですこの呼び出しで parallelフラグを変更してここでのカウント操作:

long count = StreamSupport.stream(newIterable.spliterator(), *true*).count(); 
関連する問題