Bir Java Koleksiyonunu filtrelemenin en iyi yolu nedir?


Yanıtlar:


699

Java 8 ( 2014 ) bu sorunu bir kod satırında akışlar ve lambdalar kullanarak çözer:

List<Person> beerDrinkers = persons.stream()
    .filter(p -> p.getAge() > 16).collect(Collectors.toList());

İşte bir öğretici .

Collection#removeIfKoleksiyonu yerinde değiştirmek için kullanın . (Uyarı: Bu durumda yüklem, yüklemi tatmin eden nesneleri kaldırır):

persons.removeIf(p -> p.getAge() <= 16);

lambdaj , döngüler veya iç sınıflar yazmadan koleksiyonları filtrelemenize izin verir:

List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
    greaterThan(16)));

Daha okunabilir bir şey hayal edebiliyor musunuz?

Feragatname: Ben lambdaj'a katkıda bulunuyorum


34
Güzel ama statik ithalat ne olup bittiğini gizliyor. Başvuru için, seçmek / sahip / üzerinde ch.lambdaj.Lambda statik ithalat vardır, GreaterThan org.hamcrest.Matchers olduğunu
MikePatel

11
LambdaJ gerçekten seksi, ama önemli bir yükü (ortalama 2.6) ima ettiğini belirtmekte fayda var: code.google.com/p/lambdaj/wiki/PerformanceAnalysis .
Doktor Davluz

7
Görünüşe göre Android'de çalışmıyor: groups.google.com/forum/#!msg/lambdaj/km7uFgvSd3k/grJhgl3ik5sJ
Moritz

7
Gerçekten LamdaJ bu örnek gibi ... .NET yerleşik Lambda fonksiyonları benzer. Ve bir kişi 16 yaşında nerede içebilir? Bir yerelleştirme kısıtlaması eklemeyi düşünmeliyiz. : P
MAbraham1

3
removeIf örneği olmalıdırpersons.removeIf(p -> p.getAge() <= 16);
vim

223

Java 1.5 kullandığınızı ve Google Koleksiyonlarını ekleyemeyeceğinizi varsayarsak, Google'ın yaptıklarına çok benzer bir şey yaparım. Bu Jon'un yorumlarında ufak bir değişikliktir.

Önce bu arayüzü kod tabanınıza ekleyin.

public interface IPredicate<T> { boolean apply(T type); }

Uygulayıcıları, belirli bir yüklem belirli bir tür için doğru olduğunda cevap verebilir. Örneğin Eğer Tvardı Userve AuthorizedUserPredicate<User>uygular IPredicate<T>, daha sonra AuthorizedUserPredicate#applygeçirilen olup olmadığını döndürür Useryetkilidir.

Sonra bazı yardımcı program sınıflarında,

public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
    Collection<T> result = new ArrayList<T>();
    for (T element: target) {
        if (predicate.apply(element)) {
            result.add(element);
        }
    }
    return result;
}

Yukarıdakilerin kullanımına sahip olduğunuzu varsayarsak,

Predicate<User> isAuthorized = new Predicate<User>() {
    public boolean apply(User user) {
        // binds a boolean method in User to a reference
        return user.isAuthorized();
    }
};
// allUsers is a Collection<User>
Collection<User> authorizedUsers = filter(allUsers, isAuthorized);

Doğrusal denetimdeki performans endişe ediyorsa, hedef koleksiyona sahip bir etki alanı nesnesine sahip olmak isteyebilirim. Hedef koleksiyona sahip etki alanı nesnesinin, hedef koleksiyonu başlatan, ekleyen ve ayarlayan yöntemler için filtreleme mantığı olacaktır.

GÜNCELLEME:

Yardımcı program sınıfında (Diyelim ki Tahmin), yüklem beklenen değeri döndürmediğinde varsayılan değer için bir seçenek içeren bir seçme yöntemi ve ayrıca yeni IPredicate içinde kullanılacak parametreler için statik bir özellik ekledim.

public class Predicate {
    public static Object predicateParams;

    public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
        Collection<T> result = new ArrayList<T>();
        for (T element : target) {
            if (predicate.apply(element)) {
                result.add(element);
            }
        }
        return result;
    }

    public static <T> T select(Collection<T> target, IPredicate<T> predicate) {
        T result = null;
        for (T element : target) {
            if (!predicate.apply(element))
                continue;
            result = element;
            break;
        }
        return result;
    }

    public static <T> T select(Collection<T> target, IPredicate<T> predicate, T defaultValue) {
        T result = defaultValue;
        for (T element : target) {
            if (!predicate.apply(element))
                continue;
            result = element;
            break;
        }
        return result;
    }
}

Aşağıdaki örnek koleksiyonlar arasında eksik nesneleri arar:

List<MyTypeA> missingObjects = (List<MyTypeA>) Predicate.filter(myCollectionOfA,
    new IPredicate<MyTypeA>() {
        public boolean apply(MyTypeA objectOfA) {
            Predicate.predicateParams = objectOfA.getName();
            return Predicate.select(myCollectionB, new IPredicate<MyTypeB>() {
                public boolean apply(MyTypeB objectOfB) {
                    return objectOfB.getName().equals(Predicate.predicateParams.toString());
                }
            }) == null;
        }
    });

Aşağıdaki örnek, koleksiyondaki bir örneği arar ve örnek bulunmadığında koleksiyonun ilk öğesini varsayılan değer olarak döndürür:

MyType myObject = Predicate.select(collectionOfMyType, new IPredicate<MyType>() {
public boolean apply(MyType objectOfMyType) {
    return objectOfMyType.isDefault();
}}, collectionOfMyType.get(0));

GÜNCELLEME (Java 8 sürümünden sonra):

Ben (Alan) bu cevabı ilk kez yayınladığımdan beri birkaç yıl geçti ve hala bu cevap için SO puanları topladığımı düşünemiyorum. Her halükarda, Java 8 dile dilleri kapattığına göre, cevabım şimdi oldukça farklı ve daha basit olacaktı. Java 8 ile, farklı bir statik yardımcı program sınıfına gerek yoktur. Öyleyse yükleminizle eşleşen 1. elemanı bulmak istiyorsanız.

final UserService userService = ... // perhaps injected IoC
final Optional<UserModel> userOption = userCollection.stream().filter(u -> {
    boolean isAuthorized = userService.isAuthorized(u);
    return isAuthorized;
}).findFirst();

Opsiyonel malzemeler için JDK 8 API yeteneğine sahiptir get(), isPresent(), orElse(defaultUser), orElseGet(userSupplier)ve orElseThrow(exceptionSupplier)yanı sıra, bu tür başka 'monadik' fonksiyonlar map, flatMapve filter.

Yüklemeyle eşleşen tüm kullanıcıları toplamak istiyorsanız Collectors, istenen koleksiyondaki akışı sonlandırmak için.

final UserService userService = ... // perhaps injected IoC
final List<UserModel> userOption = userCollection.stream().filter(u -> {
    boolean isAuthorized = userService.isAuthorized(u);
    return isAuthorized;
}).collect(Collectors.toList());

Java 8 akışlarının nasıl çalıştığı hakkında daha fazla örnek için buraya bakın .


27
Evet, ama tekrar tekrar tekerleği yeniden keşfetmekten nefret ediyorum. İstediğim zaman yararlanan bir yardımcı program kütüphanesi bulmayı tercih ederim.
Kevin Wong

2
Yeni koleksiyonu istemiyorsanız en iyi yol bu değildir. Yeni bir koleksiyona girebilecek veya tek ihtiyacınız olan filtre yineleyici metaforunu kullanın.
Josh

@Nestor: Scala anlayışında filtreleme çok daha kolay olurdu:val authorized = for (user <- users if user.isAuthorized) yield user
Alan

Bu orijinal koleksiyonu değiştirir mi yoksa yeni bir koleksiyon oluşturur mu? Bu yöntemi kullanarak denedim ve hem koleksiyonlarımı (orijinal ve yöntemden döndürülen) günlüğe kaydetti, aynı. @Alan
Rohan

1
@Rohan, bu orijinal koleksiyonu değiştirmek anlamına gelmez. Yukarıdaki sonuç koleksiyonunun yeni oluşturulduğunu ve filtre yönteminin yalnızca yüklem geçerliyse sonuç koleksiyonuna eklendiğini unutmayın.
Alan

92

3
Bu iyi, ama genel değil ve koleksiyon yerinde (hoş değil) değiştirir
Kevin Wong

2
CollectionUtils içinde özgün koleksiyonu değiştirmeyen başka filtre yöntemleri vardır.
skaffman

42
Özellikle, yok yöntem değil yerinde koleksiyon değiştirmek olduğunu org.apache.commons.collections.CollectionUtils # (Koleksiyonu, Yüklem) seçmek
Eero

5
Commons Collections v4'te artık Generics kullanılıyor.
Justin Emery

1
Bu yöntem, koleksiyonlar için isteğe bağlı olan iterator.remove () yöntemine dayandığı için (en azından commons-collections-3.2.1 uygulamasında) dikkatli kullanılmalıdır. Bu nedenle, örneğin bir dizi filtrelemek yerine bir UnsupportedOperationException edinin.
user2417480

67

"En iyi" yol çok geniş bir istek. "En kısa" mı? "En hızlı"? "Okunabilir"? Yerine veya başka bir koleksiyona filtre uygulamak?

En basit (ancak en okunaklı olmayan) yol, yineleme ve Iterator.remove () yöntemini kullanmaktır:

Iterator<Foo> it = col.iterator();
while( it.hasNext() ) {
  Foo foo = it.next();
  if( !condition(foo) ) it.remove();
}

Şimdi, daha okunabilir hale getirmek için, bir yardımcı program yöntemine sarabilirsiniz. Sonra bir IPredicate arabirimi icat edin, bu arabirimin anonim bir uygulamasını oluşturun ve aşağıdaki gibi bir şey yapın:

CollectionUtils.filterInPlace(col,
  new IPredicate<Foo>(){
    public boolean keepIt(Foo foo) {
      return foo.isBar();
    }
  });

Burada filterInPlace () koleksiyonu yineler ve koleksiyonda saklanacak örneğin olup olmadığını öğrenmek için Predicate.keepIt () öğesini çağırır.

Sadece bu görev için bir üçüncü taraf kütüphanesi getirmenin bir gerekçesi görmüyorum.


6
Oyum bunun için geçerli: sadece harici kütüphaneler olmadan çalışıyor. Bir yineleyiciyi başlatmanın, her sözdizimi kullanımına kıyasla gerçekten yararlı olabileceğini veya bir ConcurrentModificationException veya bunun gibi bir şey olmadan bir listeden öğe kaldırabileceğinizi fark etmedim. :)
ZeroOne

1
Bence bu kopyalamadan standart Java lib kullanmanın en iyi yolu. 1.8 için stream()özellik olurdu , ancak herkes en yeni oyuncaklar ile oynamaya
başlayamaz

Bu, orijinal koleksiyonu da değiştiriyor mu? @ZeroOne
Rohan

Evet tabii ki öyle, @Rohan. Eğer inanmıyorsanız deneyin. ;)
ZeroOne

Haha yaptım! Ama orijinal koleksiyonumu korumak istiyorum. Harici bir lib eklemeden bunu yapmanın bir yolunu önerebilir misiniz? @ZeroOne
Rohan

62

Jenerikleri destekleyen güncellenmiş bir Koleksiyonlar çerçevesi için Google Koleksiyonlar'ı düşünün .

GÜNCELLEME : Google koleksiyon kitaplığı artık kullanımdan kaldırıldı. Bunun yerine Guava'nın en son sürümünü kullanmalısınız. Tahmine dayalı bir filtreleme mekanizması da dahil olmak üzere koleksiyon çerçevesiyle aynı uzantılara sahiptir.


Evet, Google koleksiyonları lib'ini biliyordum. Kullandığım versiyonda Koleksiyon2 yoktu. Bu soruya, belirli yöntemi listeleyen yeni bir yanıt ekledim.
Kevin Wong

7
Kevin, Iterables.filter () ve Iterators.filter () en başından beri oradadır ve genellikle ihtiyacınız olan her şeydir.
Kevin Bourrillion

28

Java 8'i bekleyin:

List<Person> olderThan30 = 
  //Create a Stream from the personList
  personList.stream().
  //filter the element to select only those with age >= 30
  filter(p -> p.age >= 30).
  //put those filtered elements into a new List.
  collect(Collectors.toList());

13
Ugh ... çok ayrıntılı. Neden yapamadılar: <Person> sonuç = personList.filter (p -> p.age> 30) öğesini listeleyin;
Kevin Wong

8
Filtreyi doğrudan Koleksiyon'da kullanmak için removeIf aramasını kullanmanız gerekir : download.java.net/jdk8/docs/api/java/util/…
gavenkoa 7:13

6
@KevinWong "ayrıntılı" hemen hemen düşündüğüm dili anlatıyor. En azından tutarlılar mı?
Rogue

5
Son bölümde neden Collectors.toList () kullanılmıyor?
Nestor Hernandez Loli

3
İşte 404 değil sağlanan bir bağlantı gavenkoa. personList.removeIf(p -> p.age < 30);Daha az ayrıntılı. Ayrıca, s çok yararlı ve hızlı olduğu için s Streamyerine kabul eden ve geri dönen apisleri uygulamaya başlama hakkında konuştuklarını duydum . CollectionStream
Kaptan Adam

11

Java 8'in ilk sürümünden bu yana, aşağıdaki gibi bir şey deneyebilirsiniz:

Collection<T> collection = ...;
Stream<T> stream = collection.stream().filter(...);

Örneğin, bir tamsayılar listeniz varsa ve> 10'dan büyük sayıları filtrelemek ve ardından bu sayıları konsola yazdırmak istiyorsanız, şöyle bir şey yapabilirsiniz:

List<Integer> numbers = Arrays.asList(12, 74, 5, 8, 16);
numbers.stream().filter(n -> n > 10).forEach(System.out::println);

11

Android'de de mevcut olan ringe RxJava fırlatacağım . RxJava her zaman en iyi seçenek olmayabilir, ancak toplama sırasında daha fazla dönüşüm eklemek veya filtreleme sırasında hataları işlemek isterseniz size daha fazla esneklik sağlar.

Observable.from(Arrays.asList(1, 2, 3, 4, 5))
    .filter(new Func1<Integer, Boolean>() {
        public Boolean call(Integer i) {
            return i % 2 != 0;
        }
    })
    .subscribe(new Action1<Integer>() {
        public void call(Integer i) {
            System.out.println(i);
        }
    });

Çıktı:

1
3
5

RxJava en hakkında daha fazla ayrıntı filterbulunabilir burada .


7

Kurulum:

public interface Predicate<T> {
  public boolean filter(T t);
}

void filterCollection(Collection<T> col, Predicate<T> predicate) {
  for (Iterator i = col.iterator(); i.hasNext();) {
    T obj = i.next();
    if (predicate.filter(obj)) {
      i.remove();
    }
  }
}

Kullanım:

List<MyObject> myList = ...;
filterCollection(myList, new Predicate<MyObject>() {
  public boolean filter(MyObject obj) {
    return obj.shouldFilter();
  }
});

2
Güzel, ama Alan uygulamasını tercih ediyorum çünkü koleksiyonu değiştirmek yerine bir kopyasını alıyorsunuz. Dahası, Alan'ın kodu sizin değilken iş parçacığı için güvenlidir.
marcospereira

7

Bazı sade ve hızlı Java'ya ne dersiniz?

 List<Customer> list ...;
 List<Customer> newList = new ArrayList<>();
 for (Customer c : list){
    if (c.getName().equals("dd")) newList.add(c);
 }

Basit, okunabilir ve kolay (ve Android'de çalışıyor!) Ancak Java 8 kullanıyorsanız, bunu tatlı bir satırda yapabilirsiniz:

List<Customer> newList = list.stream().filter(c -> c.getName().equals("dd")).collect(toList());

ToList () işlevinin statik olarak içe aktarıldığını unutmayın



7

Eclipse Koleksiyonlarını kullanarak yerleşik bir JDK Listesi'ne ve bir MutableList'e nasıl filtre uygulanacağına bakalım .

List<Integer> jdkList = Arrays.asList(1, 2, 3, 4, 5);
MutableList<Integer> ecList = Lists.mutable.with(1, 2, 3, 4, 5);

3'ten küçük sayıları filtrelemek isterseniz, aşağıdaki çıktıları beklersiniz.

List<Integer> selected = Lists.mutable.with(1, 2);
List<Integer> rejected = Lists.mutable.with(3, 4, 5);

Java 8 lambda'yı kullanarak nasıl filtreleyebileceğiniz aşağıda açıklanmıştır Predicate.

Assert.assertEquals(selected, Iterate.select(jdkList, each -> each < 3));
Assert.assertEquals(rejected, Iterate.reject(jdkList, each -> each < 3));

Assert.assertEquals(selected, ecList.select(each -> each < 3));
Assert.assertEquals(rejected, ecList.reject(each -> each < 3));

Anonim bir iç sınıfı kullanarak Predicate.

Predicate<Integer> lessThan3 = new Predicate<Integer>()
{
    public boolean accept(Integer each)
    {
        return each < 3;
    }
};

Assert.assertEquals(selected, Iterate.select(jdkList, lessThan3));
Assert.assertEquals(selected, ecList.select(lessThan3));

Aşağıda , Predicates fabrikasını kullanarak JDK listelerini ve Eclipse Collections MutableLists öğelerini filtrelemenin bazı alternatifleri bulunmaktadır .

Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));
Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));

Burada, bir yöntemi kullanan Predicates2 fabrikasını kullanarak yüklem için bir nesne ayırmayan bir sürüm .selectWithPredicate2

Assert.assertEquals(
    selected, ecList.selectWith(Predicates2.<Integer>lessThan(), 3));

Bazen olumsuz bir duruma filtre uygulamak istersiniz. Eclipse Collections'da bunun için özel bir yöntem var reject.

Assert.assertEquals(rejected, Iterate.reject(jdkList, lessThan3));
Assert.assertEquals(rejected, ecList.reject(lessThan3));

Yöntem partition, tarafından seçilen ve tarafından reddedilen öğeleri içeren iki koleksiyon döndürür Predicate.

PartitionIterable<Integer> jdkPartitioned = Iterate.partition(jdkList, lessThan3);
Assert.assertEquals(selected, jdkPartitioned.getSelected());
Assert.assertEquals(rejected, jdkPartitioned.getRejected());

PartitionList<Integer> ecPartitioned = gscList.partition(lessThan3);
Assert.assertEquals(selected, ecPartitioned.getSelected());
Assert.assertEquals(rejected, ecPartitioned.getRejected());

Not: Eclipse Collections için bir komisyoncuyum.


1
removeIfBir listede veya ilkel için ayarlanmış bir öğeyi nasıl yaparsınız ?
Vivek Rao

RemoveIf için API, EC 9.1'deki ilkel koleksiyonlara eklendi. eclipse.org/collections/javadoc/9.1.0/org/eclipse/collections/…
Donald Raab

5

ForEach DSL ile şunları yazabilirsiniz:

import static ch.akuhn.util.query.Query.select;
import static ch.akuhn.util.query.Query.$result;
import ch.akuhn.util.query.Select;

Collection<String> collection = ...

for (Select<String> each : select(collection)) {
    each.yield = each.value.length() > 3;
}

Collection<String> result = $result();

[Hızlı, kahverengi, tilki, üzerinde, tembel, köpek, atlar] bir koleksiyon göz önüne alındığında, bu [hızlı, kahverengi, atlar, üzerinde, tembel], yani tüm karakter üç karakterden uzun.

ForEach DSL tarafından desteklenen tüm yineleme stilleri

  • AllSatisfy
  • AnySatisfy
  • Collect
  • Counnt
  • CutPieces
  • Detect
  • GroupedBy
  • IndexOf
  • InjectInto
  • Reject
  • Select

Daha fazla ayrıntı için lütfen https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEach adresine bakın.


Oldukça akıllı! Yine de güzel bir Ruby-ish sözdizimi uygulamak için çok iş! Negatif, filtrenizin birinci sınıf bir işlev olmaması ve dolayısıyla tekrar kullanılamamasıdır. Kapakları
kapat

İyi bir nokta. Döngü gövdesini yeniden kullanmanın bir yolu, döngüyü seçim sorgusunu parametre olarak alan bir yönteme yeniden etkinleştirmektir. Ancak bu, gerçek kapanışlar kadar açık ve güçlü değildir.
akuhn


5

Yana java 9 Collectors.filtering etkindir:

public static <T, A, R>
    Collector<T, ?, R> filtering(Predicate<? super T> predicate,
                                 Collector<? super T, A, R> downstream)

Bu nedenle filtreleme şu şekilde olmalıdır:

collection.stream().collect(Collectors.filtering(predicate, collector))

Misal:

List<Integer> oddNumbers = List.of(1, 19, 15, 10, -10).stream()
            .collect(Collectors.filtering(i -> i % 2 == 1, Collectors.toList()));

3

Bu, gerçek kapanmaların olmamasıyla birlikte, Java için en büyük tutkum. Dürüst olmak gerekirse, yukarıda bahsedilen yöntemlerin çoğunun okunması oldukça kolaydır ve GERÇEKTEN etkilidir; ancak .Net, Erlang, vb. Dil düzeyinde eklemeler olmadan, Java bu alandaki diğer diller kadar temiz olamaz.

Performans büyük bir endişe ise, Google koleksiyonları gitmenin (veya kendi basit yüklem yardımcı programınızın) yoludur. Lambdaj sözdizimi bazı insanlar için daha okunabilir, ancak oldukça etkili değildir.

Sonra yazdığım bir kütüphane var. Verimliliği ile ilgili herhangi bir soruyu görmezden geleceğim (evet, bu kadar kötü) ...... Evet, açıkça yansıma tabanlı olduğunu biliyorum ve hayır aslında kullanmıyorum, ama işe yarıyor:

LinkedList<Person> list = ......
LinkedList<Person> filtered = 
           Query.from(list).where(Condition.ensure("age", Op.GTE, 21));

VEYA

LinkedList<Person> list = ....
LinkedList<Person> filtered = Query.from(list).where("x => x.age >= 21");

Bağlantı? Kütüphaneniz verimsiz veya başka türlü kullanılamıyor olsa bile, kaynağın mevcut olup olmadığına bakmak ilginç olabilir.
MatrixFrog

Repoyu herkese açık hale getirin ( net-machine.com/indefero/p/jdclib/source/tree/master ). İfade paketiyle ilgileniyorsunuz. Test paketinin örnek kullanımlı bir test cihazı vardır. Ben gerçekten çok (yukarıda gerçek bir ayrıştırıcı yazma gibi hissetmedim) dize sorgu arabirimi üzerinde çok iş yaptım, böylece test açık sorgu arabirimi gitmek için bir yoldur.
jdc0589

2

JFilter http://code.google.com/p/jfilter/ gereksinimlerinize en uygun olanıdır .

JFilter Java fasulye toplama sorgulamak için basit ve yüksek performanslı bir açık kaynak kütüphanedir.

Ana Özellikler

  • Toplama (java.util.Collection, java.util.Map ve Array) özelliklerinin desteklenmesi.
  • Herhangi bir derinlikte toplama içinde toplama desteği.
  • İç sorguların desteklenmesi.
  • Parametreli sorguların desteklenmesi.
  • Birkaç 100 ms'de 1 milyon kayıt filtreleyebilir.
  • Filtre (sorgu) basit json formatında verilir, Mangodb sorguları gibidir. Aşağıda bazı örnekler verilmiştir.
  • {"id": {"$ le": "10"}
    • burada nesne kimliği özelliği 10'a eşittir.
  • {"id": {"$ in": ["0", "100"]}}
    • burada nesne kimliği özelliği 0 veya 100'dür.
  • { "Satır öğesi": { "lineAmount": "1"}}
    • Burada, parametrelenmiş türün lineItems collection özelliğinde lineAmount 1'e eşittir.
  • {"$ ve": [{"id": "0"}, {"billingAddress": {"şehir": "DEL"}}]}
    • burada id özelliği 0 ve billingAddress.city özelliği DEL'dir.
  • {"lineItems": {"vergiler": {"anahtar": {"kod": "GST"}, "değer": {"$ gt": "1.01"}}}}
    • burada parametredize türün vergi eşleme türü özelliğine sahip parametrelenmiş türün lineItems collection özelliği, 1.01'den büyük GST değerine eşit olan bir koda sahiptir.
  • {'$ veya': [{'kod': '10'}, {'skus': {'$ ve': [{'fiyat': {'$ in': ['20', '40']} }, {'kod': 'RedApple'}]}}}]}
    • Ürün kodunun 10 veya sku fiyatının 20 ve 40 ve sku kodunun "RedApple" olduğu tüm ürünleri seçin.

1
Yazar olduğunuzu reddetmelisiniz (bence durum böyledir).
assylias

Evet, ben bu kütüphanenin yazarıyım.
Kamran Ali Khan

2

Koleksiyon içeriğini kopyalamadan fonksiyonel algoritmaların uygulanmasını destekleyen genişletilmiş yinelenebilir bir sınıf yazdım .

Kullanımı:

List<Integer> myList = new ArrayList<Integer>(){ 1, 2, 3, 4, 5 }

Iterable<Integer> filtered = Iterable.wrap(myList).select(new Predicate1<Integer>()
{
    public Boolean call(Integer n) throws FunctionalException
    {
        return n % 2 == 0;
    }
})

for( int n : filtered )
{
    System.out.println(n);
}

Yukarıdaki kod aslında

for( int n : myList )
{
    if( n % 2 == 0 ) 
    {
        System.out.println(n);
    }
}


2

Burada gerçekten harika cevaplar var. Ben, incileri olabildiğince basit ve okunabilir tutmak istiyorum:

public abstract class AbstractFilter<T> {

    /**
     * Method that returns whether an item is to be included or not.
     * @param item an item from the given collection.
     * @return true if this item is to be included in the collection, false in case it has to be removed.
     */
    protected abstract boolean excludeItem(T item);

    public void filter(Collection<T> collection) {
        if (CollectionUtils.isNotEmpty(collection)) {
            Iterator<T> iterator = collection.iterator();
            while (iterator.hasNext()) {
                if (excludeItem(iterator.next())) {
                    iterator.remove();
                }
            }
        }
    }
}

Filtre başına uygun excludeItem öğesini uygulamanız yeterlidir. Koleksiyonlar'da sıralayıcılara sahip olduğunuz gibi ayrı filtrelere sahip olursunuz ...
Lawrence

1

Basit Java8 öncesi çözümü:

ArrayList<Item> filtered = new ArrayList<Item>(); 
for (Item item : items) if (condition(item)) filtered.add(item);

Ne yazık ki bu çözüm, verilen koleksiyonun türünden ziyade bir liste çıkartarak tamamen genel değildir. Ayrıca, kitaplık getirmek veya bu kodu saran işlevler yazmak, durum karmaşık olmadığı sürece bana aşırı yüklenme gibi geliyor, ancak daha sonra koşul için bir işlev yazabilirsiniz.


1

https://code.google.com/p/joquery/

Farklı olasılıkları destekler,

Verilen koleksiyon,

Collection<Dto> testList = new ArrayList<>();

türünde,

class Dto
{
    private int id;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getText()
    {
        return text;
    }
}

filtre

Java 7

Filter<Dto> query = CQ.<Dto>filter(testList)
    .where()
    .property("id").eq().value(1);
Collection<Dto> filtered = query.list();

Java 8

Filter<Dto> query = CQ.<Dto>filter(testList)
    .where()
    .property(Dto::getId)
    .eq().value(1);
Collection<Dto> filtered = query.list();

Ayrıca,

Filter<Dto> query = CQ.<Dto>filter()
        .from(testList)
        .where()
        .property(Dto::getId).between().value(1).value(2)
        .and()
        .property(Dto::grtText).in().value(new string[]{"a","b"});

Sıralama (Java 7 için de mevcuttur)

Filter<Dto> query = CQ.<Dto>filter(testList)
        .orderBy()
        .property(Dto::getId)
        .property(Dto::getName)
    Collection<Dto> sorted = query.list();

Gruplama (Java 7 için de mevcuttur)

GroupQuery<Integer,Dto> query = CQ.<Dto,Dto>query(testList)
        .group()
        .groupBy(Dto::getId)
    Collection<Grouping<Integer,Dto>> grouped = query.list();

Birleşimler (Java 7 için de mevcuttur)

göz önüne alındığında,

class LeftDto
{
    private int id;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getText()
    {
        return text;
    }
}

class RightDto
{
    private int id;
    private int leftId;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getLeftId()
        {
            return leftId;
        }

    public int getText()
    {
        return text;
    }
}

class JoinedDto
{
    private int leftId;
    private int rightId;
    private String text;

    public JoinedDto(int leftId,int rightId,String text)
    {
        this.leftId = leftId;
        this.rightId = rightId;
        this.text = text;
    }

    public int getLeftId()
    {
        return leftId;
    }

    public int getRightId()
        {
            return rightId;
        }

    public int getText()
    {
        return text;
    }
}

Collection<LeftDto> leftList = new ArrayList<>();

Collection<RightDto> rightList = new ArrayList<>();

Gibi Katılabilir,

Collection<JoinedDto> results = CQ.<LeftDto, LeftDto>query().from(leftList)
                .<RightDto, JoinedDto>innerJoin(CQ.<RightDto, RightDto>query().from(rightList))
                .on(LeftFyo::getId, RightDto::getLeftId)
                .transformDirect(selection ->  new JoinedDto(selection.getLeft().getText()
                                                     , selection.getLeft().getId()
                                                     , selection.getRight().getId())
                                 )
                .list();

İfade

Filter<Dto> query = CQ.<Dto>filter()
    .from(testList)
    .where()
    .exec(s -> s.getId() + 1).eq().value(2);

1

Benim cevabım kullanarak tek astar olarak burada Kevin Wong o üzerine inşa CollectionUtilsgelen ilkbahar ve Java 8 lambda ifadesi.

CollectionUtils.filter(list, p -> ((Person) p).getAge() > 16);

Bu gördüğüm herhangi bir alternatif kadar özlü ve okunabilir (en boy tabanlı kütüphaneler kullanmadan)

Spring CollectionUtils , ilkbahar 4.0.2 sürümünden itibaren kullanılabilir.


1

Kullanılması java 8özellikle lambda expression, sadece örnek aşağıda gibi yapabilirsiniz:

myProducts.stream().filter(prod -> prod.price>10).collect(Collectors.toList())

her productmyProductskoleksiyon için, eğer varsa prod.price>10, bu ürünü yeni filtrelenmiş listeye ekleyin.


1

Listede bulunan değerlere bağlı olarak bir listeyi filtrelemem gerekiyordu. Örneğin, geçerli değerden küçük olan tüm değerleri kaldırın. {2 5 3 4 7 5} -> {2 5 7}. Veya örneğin tüm kopyaları kaldırmak için {3 5 4 2 3 5 6} -> {3 5 4 2 6}.

public class Filter {
    public static <T> void List(List<T> list, Chooser<T> chooser) {
        List<Integer> toBeRemoved = new ArrayList<>();
        leftloop:
        for (int right = 1; right < list.size(); ++right) {
            for (int left = 0; left < right; ++left) {
                if (toBeRemoved.contains(left)) {
                    continue;
                }
                Keep keep = chooser.choose(list.get(left), list.get(right));
                switch (keep) {
                    case LEFT:
                        toBeRemoved.add(right);
                        continue leftloop;
                    case RIGHT:
                        toBeRemoved.add(left);
                        break;
                    case NONE:
                        toBeRemoved.add(left);
                        toBeRemoved.add(right);
                        continue leftloop;
                }
            }
        }

        Collections.sort(toBeRemoved, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });

        for (int i : toBeRemoved) {
            if (i >= 0 && i < list.size()) {
                list.remove(i);
            }
        }
    }

    public static <T> void List(List<T> list, Keeper<T> keeper) {
        Iterator<T> iterator = list.iterator();
        while (iterator.hasNext()) {
            if (!keeper.keep(iterator.next())) {
                iterator.remove();
            }
        }
    }

    public interface Keeper<E> {
        boolean keep(E obj);
    }

    public interface Chooser<E> {
        Keep choose(E left, E right);
    }

    public enum Keep {
        LEFT, RIGHT, BOTH, NONE;
    }
}

Bu arı böyle kullanılır.

List<String> names = new ArrayList<>();
names.add("Anders");
names.add("Stefan");
names.add("Anders");
Filter.List(names, new Filter.Chooser<String>() {
    @Override
    public Filter.Keep choose(String left, String right) {
        return left.equals(right) ? Filter.Keep.LEFT : Filter.Keep.BOTH;
    }
});

0

Guava ile:

Collection<Integer> collection = Lists.newArrayList(1, 2, 3, 4, 5);

Iterators.removeIf(collection.iterator(), new Predicate<Integer>() {
    @Override
    public boolean apply(Integer i) {
        return i % 2 == 0;
    }
});

System.out.println(collection); // Prints 1, 3, 5

0

Java 8'de, doğrudan bu filtre yöntemini kullanabilir ve sonra bunu yapabilirsiniz.

 List<String> lines = Arrays.asList("java", "pramod", "example");

 List<String> result = lines.stream()              
         .filter(line -> !"pramod".equals(line))     
         .collect(Collectors.toList());              

 result.forEach(System.out::println); 
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.