イテレータのカウントを取得する「計算上」簡単な方法はありますか?
int i = 0;
for ( ; some_iterator.hasNext() ; ++i ) some_iterator.next();
... CPUサイクルの無駄のようです。
イテレータを取得したら、それがあなたがしなければならないことです-それはknow反復するために残されたアイテムの数ではないので、その結果をクエリすることはできません。これを行うように思われるユーティリティメソッド(グアバのIterators.size()
など)がありますが、それらの下ではほぼ同じ操作を実行しています。
ただし、多くのイテレータはコレクションから取得されるため、コレクションのサイズを頻繁に照会できます。また、イテレータを取得するユーザー作成クラスの場合は、そのクラスでsize()メソッドを提供することを検討できます。
要するに、only反復子を持っている状況では、より良い方法はありませんが、多くの場合、サイズを取得できる基になるコレクションまたはオブジェクトにアクセスできます直接。
イテレータの最後に到達すると、コードで例外が発生します。できること:
int i = 0;
while(iterator.hasNext()) {
i++;
iterator.next();
}
基礎となるコレクションにアクセスできる場合、coll.size()
...を呼び出すことができます。
EDIT OK修正しました...
常に反復する必要があります。それでも、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();
Guavaライブラリ を使用する別のオプションは、Iterable
をList
に変換することです。
List list = Lists.newArrayList(some_iterator);
int count = list.size();
イテレータのサイズを取得した後、イテレータの要素にもアクセスする必要がある場合、これを使用します。 Iterators.size()
を使用すると、反復された要素にアクセスできなくなります。
持っているのがイテレータだけなら、いや、「より良い」方法はありません。イテレータがコレクションからのものである場合は、サイズについても同様です。
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");
}
};
反復子さえあれば、これ以上効率的な方法はありません。そして、イテレータが一度しか使用できない場合、イテレータの内容を取得する前にカウントを取得することは問題です。
解決策は、カウントを必要としないようにアプリケーションを変更するか、他の方法でカウントを取得することです。 (たとえば、Collection
ではなくIterator
を渡します...)