Guava: Lists.filter () işlevi neden yok?


86

Bir sebebi var mı

Lists.transform()

ama hayır

Lists.filter()

?

Bir listeyi nasıl doğru bir şekilde filtrelerim? kullanabilirim

new ArrayList(Collection2.filter())

Tabii ki, ancak bu şekilde, doğru anlarsam, siparişimin aynı kalacağı garanti edilmez.


8
Bilginize, List.newArrayList (Iterables.filter (...)) genellikle yeni ArrayList'den (Collection2.filter (...)) daha hızlıdır. ArrayList yapıcısı, filtrelenmiş koleksiyonda size () öğesini çağırır ve boyutu hesaplamak, filtrenin orijinal listenin her öğesine uygulanmasını gerektirir.
Jared Levy

4
@JaredLevy Belki yerine List.newArrayList(Iterables.filter(...))demeli Lists.newArrayList(Iterables.filter(...)) .
Abdull

Yanıtlar:


58

Döndürülen Liste görünümünde #get (dizin) (performans hatalarını davet eden) gibi tehlikeli çok sayıda yavaş yöntemi ortaya çıkaracağı için uygulanmadı. Ve ListIterator'ın uygulanması da bir acı olurdu ( bunu kapsamak için yıllar önce bir yama göndermiş olsam da).

Dizine alınmış yöntemler filtrelenmiş Liste görünümünde verimli olamayacağından, bunlara sahip olmayan filtrelenmiş bir Yinelenebilir ile gitmek daha iyidir.


7
Bir liste görünümünün döndürüleceğini varsayıyorsunuz. Bununla birlikte, #filter yeni bir materyalleştirilmiş liste döndürmek olarak uygulanabilir, bu aslında Iterable'daki yerine listeler için bir filtre yönteminden beklediğim şeydir.
Felix Leipold

@FelixLeipold Ancak bu suları bulandırır. Olduğu gibi, filtertutarlı bir şekilde bir görüş (ima eden davranışla birlikte) anlamına gelir Iterables.filter, Sets.filtervb . Herhangi biriyle Iterables.filterkolayca birleştiğinden , bunu iyi bir tasarım ödünleşimi buluyorum (buna karşı ekstra yöntemler ve isimler bulmak, gibi veya başka , basit yardımcı programların kombinasyonları için). copyOfImmutableCollectionfilteredCopy
Luke Usherwood

37

Iterables.filterSiparişi kesinlikle koruyacak olanı kullanabilirsiniz .

Yeni bir liste oluşturarak, öğeleri (elbette sadece referanslar) kopyalayacağınızı unutmayın - bu nedenle, orijinal listeye canlı görüntü olmayacaktır. Bir görünüm oluşturmak oldukça zor olurdu - şu durumu düşünün:

Predicate<StringBuilder> predicate = 
    /* predicate returning whether the builder is empty */
List<StringBuilder> builders = Lists.newArrayList();
List<StringBuilder> view = Lists.filter(builders, predicate);

for (int i = 0; i < 10000; i++) {
    builders.add(new StringBuilder());
}
builders.get(8000).append("bar");

StringBuilder firstNonEmpty = view.get(0);

Bu, tüm orijinal listeyi yinelemek ve filtreyi her şeye uygulamak zorunda kalacaktı. Sanırım, yüklem eşleştirmesinin görünümün ömrü boyunca değişmemesini gerektirebilir, ancak bu tamamen tatmin edici olmaz.

(Bu sadece tahmin etmektir, umursayın. Belki Guava geliştiricilerinden biri gerçek sebeple devreye girer :)


1
Collections2.filter.iteratorsadece arar Iterables.filter, dolayısıyla sonuç aynıdır.
skaffman

@skaffman: Bu durumda Iterables.filtersürümü sadece açıklık için kullanırdım .
Jon Skeet

3
... view.size()kodda daha sonra bir yere ihtiyacınız yoksa :)
Xaerxess

28

new List(Collection2.filter())Elbette kullanabilirdim , ancak bu şekilde siparişimin aynı kalacağı garanti edilmez.

Bu doğru değil. Collections2.filter()tembel olarak değerlendirilen bir işlevdir - filtrelenmiş sürüme erişmeye başlayana kadar aslında koleksiyonunuzu filtrelemez. Örneğin, filtrelenmiş sürüm üzerinde yineleme yaparsanız, filtrelenen öğeler yineleyiciden orijinal koleksiyonunuzla aynı sırada çıkacaktır (tabii ki filtrelenenler hariç).

Belki de filtrelemeyi önceden yaptığını, sonra sonuçları rastgele, sırasız bir şekilde bir koleksiyona döktüğünü düşünüyordunuz - öyle değil.

Eğer çıktısını kullanmak Yani eğer Collections2.filter()yeni bir listeye girdi olarak, sonra orijinal sipariş edecek korunacak.

Statik içe aktarımları (ve Lists.newArrayListişlevi) kullanarak, oldukça kısa ve öz hale gelir:

List filteredList = newArrayList(filter(originalList, predicate));

Ederken o Not Collections2.filterhevesle yinelerler yatan koleksiyonu üzerinde, olmaz Lists.newArrayList olur o süzülmüş koleksiyonun elemanları elde edecek ve onları yeni kopyalamak - ArrayList.


Daha çok: List filteredList = newArrayList(filter(originalList, new Predicate<T>() { @Override public boolean apply(T input) { return (...); } }));veya ie gibi . List filteredList = newArrayList(filter(originalList, Predicates.notNull()));
Xaerxess

@Xaerxess: Oops, evet, yüklemi unuttum ... düzeltildi
skaffman

@Bozho: Teşekkürler ... yeterince uzun sürdü :)
skaffman

12

Jon tarafından belirtildiği gibi, kullanabilir Iterables.filter(..)veya Collections2.filter(..)ve canlı bir görünüm gerekmiyorsa kullanabileceğiniz ImmutableList.copyOf(Iterables.filter(..))veya Lists.newArrayList( Iterables.filter(..))evet sipariş korunacaktır. Neden bölümüyle

gerçekten ilgileniyorsanız, daha fazla ayrıntı için https://github.com/google/guava/issues/505 adresini ziyaret edebilirsiniz .


6

Başkalarının söylediklerini özetleyerek, listeleri filtrelemek için kolayca genel bir sarmalayıcı oluşturabilirsiniz:

public static <T> List<T> filter(Iterable<T> userLists, Predicate<T> predicate) {
    return Lists.newArrayList(Iterables.filter(userLists, predicate));
}
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.