JavaでIterableのサイズを取得する


88

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

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

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

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

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


どうして?どちらもO(N)であるため、どちらも非常に悪い考えです。コレクションを2回繰り返す必要はありません。
ローン侯爵2012

3
あなたの2番目のものはうまくいかないはずです。事前に電話remove()せずに電話することはできませんnext()
Louis Wasserman

回答:


123

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

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

パフォーマンスについては、これはデータ構造によって異なります。たとえば、実際にはArrayList、要素を最初から削除する(2番目の方法が実行している)のは非常に遅いです(サイズの計算は、本来のO(n)ではなくO(n * n)になります)。

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

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

呼び出しは、size()通常、はるかに高速の要素の数を数えるよりなり、このトリックはまさにあるIterables.size(Iterable)グアバ、あなたのために行います。


彼は、要素には興味がなく、削除されてもかまわないと言います。
aioobe 2012

小さな明確化:それは要素を削除しますからvalues
ミケル

1
ただし、コードの他の部分でも同じIterableを使用している可能性があります。そして、今でなければ、おそらく将来的に。
フィリップウェンドラー2012

GoogleGuavaの回答をもっと目立たせることをお勧めします。些細なことですが、人々にこのコードをもう一度書かせる理由はありません。
スティーブンハリソン

8
Java 8を使用する場合は、次のようにStreamとcount要素を作成します。Stream.of(myIterable).count()
FrankBr 2016

41

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

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

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

ここでjavadocを確認できます。

Java 8がオプションでない場合、またはiterableがどこから来ているのかわからない場合は、guavaと同じアプローチを使用できます。

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

1
誰か、この男にメダルを渡してください。
PrameshBajracharya19年

ソートでは機能しません。NewBeeによる回答は私のために働きます。
サビールカーン

18

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

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

2
これは私にとって直感的なアプローチであり、私はそれを高く評価することができます。数分前に使用しました。ありがとう。
Matt Cremeens 2015

2
はい、それは直感的ですが、残念ながら、未使用の値の警告を抑制する必要があります...
Nils-o-mat

このソリューションのおかげで、それは確かにオブジェクトのサイズを返します。唯一の裏側は、後で同じオブジェクトを繰り返し処理する場合は、最初に何らかの方法でリセットする必要があることです。
Zsolti

7

iterableをリストにキャストしてから、.size()を使用できます。

Lists.newArrayList(iterable).size();

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

import com.google.common.collect.Lists;

2
リストはグアバのクラスです
Paul Jackson

6

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

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

    new Iterable(){

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

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

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

2

私は、オプションの操作である一方で、実装が保証されてit.next()いるという単純な理由で行きます。next()remove()

E next()

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

void remove()

基になるコレクションから、イテレータによって返された最後の要素を削除します(オプションの操作)


この答えは技術的には正しいですが、かなり誤解を招く恐れがあります。呼び出しremoveIterator、の要素をカウントする間違った方法としてすでに指摘されている ため、実行しないことが実装されているかどうかは実際には問題ではありません。
スティーブンハリソン

1
答えのどの部分が誤解を招くのでしょうか?そして、状況の下でremove されて実装され、なぜそれを使用する間違っているだろうか?ところで、反対票は通常、間違った答えや悪いアドバイスを与える答えに使用されます。この答えがそのいずれにもどのように当てはまるのかわかりません。
aioobe 2015


0

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


-2

要素の数を取得するために、単純にsize()メソッドを使用してみませんCollectionか?

Iterator 繰り返すことだけを目的としており、他には何もありません。


4
コレクションを使用していると誰が言いますか?:-)
aioobe 2012

要素の削除をサポートするイテレータを使用しています。イテレータループに入る前にサイズを取得する場合は、削除に注意し、それに応じて値を更新する必要があります。
ミケル2012

1
サイズを調べるコレクションがない理由の例:Iterableのみを返すサードパーティのAPIメソッドを呼び出している可能性があります。
SteveT 2012年

2
この答えは混乱IteratorIterableます。正しい方法については、投票された回答を参照してください。
スティーブンハリソン

-4

ループを使用して各要素をカウントしたり、サードパーティライブラリを使用したりする代わりに、ArrayListでイテラブルをタイプキャストしてそのサイズを取得できます。

((ArrayList) iterable).size();

3
すべての反復可能配列をArrayListにキャストできるわけではありません
AlexanderMills19年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.