100

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

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

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

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

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

4

10 に答える 10

135

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

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

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

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

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

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

于 2012-07-22T09:12:29.017 に答える
46

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;
    }
于 2016-02-26T08:48:13.590 に答える
19

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

int size = 0;
for(T value : values) {
   size++;
}
于 2013-11-01T12:39:31.777 に答える
6

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

次の Iterable インスタンスについて考えてみましょう。サイズはありません。

    new Iterable(){

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

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

                @Override
                public Object next() {
                    return fetchDataFromExternalSystem();
                }};
        }};
于 2012-07-22T09:33:15.677 に答える
2

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

E next()

繰り返しの次の要素を返します。

void remove()

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

于 2012-07-22T09:12:16.590 に答える
0

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

于 2012-07-22T09:15:02.790 に答える
-2

size()メソッドを使用してCollection要素の数を取得してみませんか?

Iterator反復するだけで、他には何もありません。

于 2012-07-22T09:10:00.863 に答える