web-dev-qa-db-ja.com

JavaのIterableのサイズを取得します

JavaのIterableの要素数を把握する必要があります。私はこれができることを知っています:

Iterable values = ...
it = values.iterator();
while (it.hasNext()) {
  it.next();
  sum++;
}

Iterableのオブジェクトはこれ以上必要ないため、次のようなこともできます。

it = values.iterator();
while (it.hasNext()) {
  it.remove();
  sum++;
}

小規模のベンチマークでは、この問題に対するパフォーマンスの違い、コメント、その他のアイデアはあまり見られませんでしたか?

73
js84

TL; DR:優れたユーティリティメソッド Iterables.size(Iterable) を使用します Guava ライブラリ。

2番目のコードスニペットでは、最初のコードスニペットを使用する必要があります。2番目のコードスニペットはvaluesからすべての要素を削除するため、後で空になるためです。サイズのような単純なクエリのデータ構造を変更することは、非常に予想外です。

パフォーマンスのために、これはデータ構造に依存します。たとえば、実際にArrayListである場合、最初から要素を削除する(2番目のメソッドが実行していること)のは非常に遅い(サイズの計算はO(n)あるべきです)。

一般に、valuesCollectionだけでなく、実際にIterableである可能性がある場合は、これを確認し、次の場合にsize()を呼び出します。

if (values instanceof Collection<?>) {
  return ((Collection<?>)values).size();
}
// use Iterator here...

size()への呼び出しは通常、要素の数を数えるよりもはるかに高速であり、このトリックは Iterables.size(Iterable) of Guava があなたのために行うこととまったく同じです。

106
Philipp Wendler

Java 8を使用している場合は、次を使用できます。

Iterable values = ...
long size = values.spliterator().getExactSizeIfKnown();

反復可能なソースのサイズが決まっている場合にのみ機能します。ほとんどのコレクション用のスプリッターは使用できますが、HashSetまたはResultSetforからの場合は問題が発生する可能性があります。

javadoc here。 を確認できます

Java 8がオプションではない場合、または反復可能オブジェクトがどこから来たのかわからない場合は、同じものを使用できますグアバとしてのアプローチ:

  if (iterable instanceof Collection) {
        return ((Collection<?>) iterable).size();
    } else {
        int count = 0;
        Iterator iterator = iterable.iterator();
        while(iterator.hasNext()) {
            iterator.next();
            count++;
        }
        return count;
    }
34
ArnaudR

これはおそらく少し遅いですが、誰かを助けるかもしれません。私は私のコードベースでIterableで同様の問題に遭遇し、解決策はvalues.iterator();を明示的に呼び出さずにfor eachを使用することでした。

int size = 0;
for(T value : values) {
   size++;
}
14
pilot

厳密に言えば、Iterableにはサイズがありません。データ構造をサイクルのように考えてください。

そして、次のIterableインスタンス、サイズなしについて考えてください:

    new Iterable(){

        @Override public Iterator iterator() {
            return new Iterator(){

                @Override
                public boolean hasNext() {
                    return isExternalSystemAvailble();
                }

                @Override
                public Object next() {
                    return fetchDataFromExternalSystem();
                }};
        }};

イテラブルをリストにキャストしてから、その上で.size()を使用できます。

Lists.newArrayList(iterable).size();

明確にするために、上記の方法では次のインポートが必要になります。

import com.google.common.collect.Lists;
5
snacks

it.next()はオプションの操作であるが、next()の実装が保証されているという簡単な理由で、remove()に進みます。

E next()

反復の次の要素を返します。

void remove()

反復子によって返された最後の要素(optional operation)を基になるコレクションから削除します。

2
aioobe

私にとっては、これらは異なる方法です。最初のものは、繰り返し処理中のオブジェクトを変更せずに残しますが、秒部分は空のままにします。問題は、あなたが何をしたいかです。削除の複雑さは、反復可能なオブジェクトの実装に基づいています。コレクションを使用している場合-風影我愛羅が提案したようなサイズを取得するだけで-通常はパフォーマンスの面で最適なアプローチです。

0
Mark Bramnik