Java'da yinelenebilir boyut alın


90

IterableJava'daki öğelerin sayısını bulmam gerekiyor. Bunu yapabileceğimi biliyorum:

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

Bunun gibi bir şey de yapabilirdim, çünkü Yinelemedeki nesnelere artık ihtiyacım yok:

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

Küçük ölçekli bir kıyaslama, bu sorun için çok fazla performans farkı, herhangi bir yorum veya başka fikir göstermedi mi?


Neden? Her ikisi de O (N) olduğu için ikisi de gerçekten kötü bir fikir. Koleksiyonu iki kez yinelemek zorunda kalmamaya çalışmalısınız.
user207421

3
İkinciniz işe yaramamalı bile. Sen diyemezsin remove()uğramadan next()önceden.
Louis Wasserman

Yanıtlar:


125

TL; DR: Iterables.size(Iterable)Harika Guava kütüphanesinin fayda yöntemini kullanın .

İki kod parçacığınızdan ilkini kullanmalısınız, çünkü ikincisi tüm öğeleri kaldıracak values, dolayısıyla daha sonra boş olacaktır. Veri yapısını, boyutu gibi basit bir sorgu için değiştirmek çok beklenmedik bir durumdur.

Performans için bu, veri yapınıza bağlıdır. Örneğin aslında bir ise ArrayList, öğeleri baştan kaldırmak (ikinci yönteminizin yaptığı şey) çok yavaştır (boyutu hesaplamak olması gerektiği gibi O (n) yerine O (n * n) olur).

Genel olarak, sadece bir değil values, aslında bir şans varsa, bunu kontrol edin ve şu durumda arayın :CollectionIterablesize()

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

Çağrı size()genellikle elementlerin sayısını saymaktan çok daha hızlı olacaktır ve bu numara tam Iterables.size(Iterable)olarak Guava'nın sizin için yaptığı şeydir .


Öğelerle ilgilenmediğini ve yine de kaldırılıp kaldırılmamasını umursamadığını söylüyor.
aioobe

Küçük açıklama: Bu elementler kaldıracaktır denvalues
Miquel

1
Ancak kodun diğer kısımları hala aynı Yinelemeyi kullanıyor olabilir. Ve şimdi değilse, belki gelecekte.
Philipp Wendler

Google Guava yanıtını daha belirgin hale getirmenizi öneririm. Önemsiz olsa da, insanların bu kodu tekrar yazmaları için hiçbir neden yok.
Stephen Harrison

8
Java 8 kullanıyorsanız, bir Akış oluşturun ve içindeki öğeyi şu şekilde sayın: Stream.of (myIterable) .count ()
FrankBr

41

Java 8 ile çalışıyorsanız şunları kullanabilirsiniz:

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

yalnızca yinelenebilir kaynağın belirli bir boyutu varsa çalışır. Bir geliyorsa Koleksiyonu için çoğu Spliterators, ancak sorunları olabilir olacak HashSetya ResultSetmesela.

Javadoc'u buradan kontrol edebilirsiniz .

Java 8 bir seçenek değilse veya yinelenebilirin nereden geldiğini bilmiyorsanız, guava ile aynı yaklaşımı kullanabilirsiniz:

  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
Biri bu adama madalya versin.
Pramesh Bajracharya

Benim için Sort için çalışmıyor . New Bee'nin cevabı benim için çalışıyor.
Sabir Khan

18

Bu belki biraz geç, ancak birine yardımcı olabilir. IterableKod tabanımda benzer bir sorunla karşılaştım ve çözüm for eachaçıkça arama yapmadan kullanmaktı values.iterator();.

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

2
Bu benim için takdir edebileceğim sezgisel bir yaklaşım. Birkaç dakika önce kullandım. Teşekkürler.
Matt Cremeens

2
Evet, sezgisel, ama ne yazık ki, kullanılmayan bir değer uyarısını bastırmanız gerekiyor ...
Nils-o-mat

Bu çözüm için teşekkürler, gerçekten de nesnenin boyutunu döndürüyor. Tek arka tarafı, aynı nesne üzerinde daha sonra tekrar yinelemek istiyorsanız, önce onu bir şekilde sıfırlamanız gerektiğidir.
Zsolti

6

Açıkçası yinelenebilir bir boyuta sahip değildir. Veri yapısını bir döngü gibi düşünün.

Ve Yinelenebilir örneği takip etmeyi düşünün, Boyut yok:

    new Iterable(){

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

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

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

6

Yinelenebilir dosyanızı bir listeye dönüştürebilir ve ardından .size () kullanabilirsiniz.

Lists.newArrayList(iterable).size();

Netlik açısından, yukarıdaki yöntem aşağıdaki içe aktarmayı gerektirecektir:

import com.google.common.collect.Lists;

3
Listeler bir Guava sınıfıdır
Paul Jackson

2

Opsiyonel bir işlem iken , uygulanması garanti it.next()edilen basit bir nedenden ötürü gidecektim .next()remove()

E next()

Yinelemedeki sonraki öğeyi döndürür.

void remove()

Yineleyici tarafından döndürülen son öğeyi temel alınan koleksiyondan kaldırır (isteğe bağlı işlem) .


Bu cevap teknik olarak doğru olsa da, oldukça yanıltıcıdır. Çağrı remove, bir öğesinin öğelerini saymanın yanlış yolu olarak zaten belirtilmişti Iterator, bu yüzden yapmayacağımız şeyin uygulanıp uygulanmayacağı gerçekten önemli değil.
Stephen Harrison

1
Cevabın tam olarak hangi kısmı yanıltıcıdır? Ve surette remove edilir uygulanan, neden kullanmak yanlış olur? Btw, olumsuz oylar tipik olarak yanlış cevaplar veya kötü tavsiye veren cevaplar için kullanılır. Bu cevabın bunlardan herhangi biri için nasıl uygun olduğunu göremiyorum.
aioobe

2

java 8 ve üstü

StreamSupport.stream(data.spliterator(), false).count();

0

Bana gelince, bunlar sadece farklı yöntemler. İlki, yinelediğiniz nesneyi değiştirmeden bırakır, saniye ise boş bırakır. Soru, ne yapmak istediğin. Kaldırmanın karmaşıklığı, yinelenebilir nesnenizin uygulanmasına bağlıdır. Koleksiyonları kullanıyorsanız - Kazekage Gaara tarafından önerilen boyuta sahip olun - genellikle performansı açısından en iyi yaklaşımdır.


-2

Öğelerin sayısını elde etmek için neden sadece size()yöntemini kullanmıyorsun Collection?

Iterator sadece yineleme amaçlıdır, başka bir şey değildir.


4
Koleksiyon kullandığını kim söyledi? :-)
aioobe

Öğelerin kaldırılmasını destekleyen bir yineleyici kullanıyorsunuz. Yineleyici döngüsüne girmeden önce boyutu alırsanız, kaldırmalarınıza dikkat etmeniz ve değeri buna göre güncellemeniz gerekir.
Miquel

1
Neden boyut olarak bakacak bir koleksiyona sahip olamayacağına bir örnek: Yalnızca bir Yinelenebilir döndüren üçüncü taraf bir API yöntemini çağırıyor olabilir.
SteveT

2
Bu cevap kafa karıştırıyor Iteratorve Iterable. Doğru yol için oylanmış cevaba bakın.
Stephen Harrison

-4

Döngüler kullanmak ve her bir öğeyi saymak veya üçüncü taraf kitaplığı kullanmak yerine, basitçe ArrayList'te yinelenebilir yazıp boyutunu elde edebiliriz.

((ArrayList) iterable).size();

3
Tüm yinelenen öğeler ArrayList'e dönüştürülemez tho
Alexander Mills
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.