web-dev-qa-db-ja.com

イテレータのカウント/長さ/サイズを取得する最良の方法は何ですか?

イテレータのカウントを取得する「計算上」簡単な方法はありますか?

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

... CPUサイクルの無駄のようです。

85
Zak

イテレータを取得したら、それがあなたがしなければならないことです-それはknow反復するために残されたアイテムの数ではないので、その結果をクエリすることはできません。これを行うように思われるユーティリティメソッド(グアバのIterators.size()など)がありますが、それらの下ではほぼ同じ操作を実行しています。

ただし、多くのイテレータはコレクションから取得されるため、コレクションのサイズを頻繁に照会できます。また、イテレータを取得するユーザー作成クラスの場合は、そのクラスでsize()メソッドを提供することを検討できます。

要するに、only反復子を持っている状況では、より良い方法はありませんが、多くの場合、サイズを取得できる基になるコレクションまたはオブジェクトにアクセスできます直接。

61
Michael Berry

Guavaライブラリ を使用:

int size = Iterators.size(iterator);

内部的には、すべての要素を繰り返し処理するだけなので、便利です。

87
Andrejs

イテレータの最後に到達すると、コードで例外が発生します。できること:

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

基礎となるコレクションにアクセスできる場合、coll.size()...を呼び出すことができます。

EDIT OK修正しました...

10
assylias

常に反復する必要があります。それでも、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();
7
gil.fernandes

Guavaライブラリ を使用する別のオプションは、IterableListに変換することです。

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

イテレータのサイズを取得した後、イテレータの要素にもアクセスする必要がある場合、これを使用します。 Iterators.size()を使用すると、反復された要素にアクセスできなくなります。

6
tashuhka

持っているのがイテレータだけなら、いや、「より良い」方法はありません。イテレータがコレクションからのものである場合は、サイズについても同様です。

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");
        }
    }; 
6
Roger Lindsjö

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

解決策は、カウントを必要としないようにアプリケーションを変更するか、他の方法でカウントを取得することです。 (たとえば、CollectionではなくIteratorを渡します...)

4
Stephen C