जावा कलेक्शन को फिल्टर करने का सबसे अच्छा तरीका क्या है?


जवाबों:


698

जावा 8 ( 2014 ) कोड की एक लाइन में स्ट्रीम और लैम्ब्डा का उपयोग करके इस समस्या को हल करता है:

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

यहाँ एक ट्यूटोरियल है

Collection#removeIfसंग्रह को संशोधित करने के लिए उपयोग करें । (सूचना: इस मामले में, विधेय उन वस्तुओं को हटा देगा जो विधेय को संतुष्ट करती हैं):

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

लैम्ब्दज लूप या इनर क्लासेस लिखे बिना संग्रह को फ़िल्टर करने की अनुमति देता है:

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

क्या आप कुछ और पठनीय कल्पना कर सकते हैं?

डिस्क्लेमर: मैं लैंबडाज में योगदानकर्ता हूं


34
अच्छा है, लेकिन स्थैतिक आयात व्हाट्सएप पर चल रहा है। संदर्भ के लिए, ch.lambdaj.Lambda पर चुनिंदा / होने / स्थैतिक आयात कर रहे हैं, अधिक से अधिक है। org.hamcrest.Matchers
माइकेल

11
लैम्बडाज वास्तव में सेक्सी है, लेकिन यह ध्यान देने योग्य है कि यह एक महत्वपूर्ण ओवरहेड (2.6 औसत) का अर्थ है: code.google.com/p/lambdaj/wiki/PerformanceAnalysis
डॉक डेव्लूज़

7
जाहिरा तौर पर एंड्रॉइड पर काम नहीं करता है: group.google.com/forum/#-msg/lambdaj/km7uFgvSd3k/grJhgl3ik5sJ
Moritz

7
वास्तव में LamdaJ के इस उदाहरण की तरह ... .NET बिल्ट-इन लैम्बडा फ़ंक्शन के समान। और एक व्यक्ति 16 साल की उम्र में कहां पी सकता है? हमें स्थानीयकरण की बाधा को जोड़ने पर विचार करना चाहिए। : P
MAbraham1

3
removeIf उदाहरण होना चाहिएpersons.removeIf(p -> p.getAge() <= 16);
vim

223

यह मानते हुए कि आप जावा 1.5 का उपयोग कर रहे हैं , और यह कि आप Google संग्रह नहीं जोड़ सकते , मैं Google लोगों द्वारा किए गए कार्यों के समान कुछ करूंगा। जॉन की टिप्पणियों पर यह थोड़ा बदलाव है।

सबसे पहले इस इंटरफ़ेस को अपने कोडबेस में जोड़ें।

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

इसके कार्यान्वयनकर्ता उत्तर दे सकते हैं जब एक निश्चित विधेय एक निश्चित प्रकार का सच होता है। उदाहरण के लिए यदि Tथे Userऔर AuthorizedUserPredicate<User>लागू करता IPredicate<T>है, तो AuthorizedUserPredicate#applyरिटर्न कि क्या में पारित Userअधिकृत है।

फिर कुछ उपयोगिता वर्ग में, आप कह सकते हैं

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;
}

तो, यह मानते हुए कि आपके पास उपरोक्त का उपयोग हो सकता है

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);

यदि लीनियर चेक पर प्रदर्शन चिंता का विषय है, तो मैं एक डोमेन ऑब्जेक्ट चाहता हूं जो लक्ष्य संग्रह है। लक्ष्य संग्रह वाले डोमेन ऑब्जेक्ट में लक्ष्य संग्रह को आरंभ, जोड़ने और सेट करने के तरीकों के लिए फ़िल्टरिंग तर्क होगा।

अपडेट करें:

उपयोगिता वर्ग में (मान लें कि विधेय कहते हैं), मैंने डिफ़ॉल्ट मान के लिए एक विकल्प के साथ एक चयन विधि जोड़ दी है जब विधेय अपेक्षित मूल्य नहीं लौटाता है, और नए IPredicate के अंदर उपयोग किए जाने वाले परम के लिए एक स्थिर संपत्ति भी है।

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;
    }
}

निम्नलिखित उदाहरण संग्रह के बीच लापता वस्तुओं की तलाश करता है:

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;
        }
    });

निम्न उदाहरण, संग्रह में एक उदाहरण के लिए दिखता है, और संग्रह का पहला तत्व डिफ़ॉल्ट मान के रूप में देता है जब उदाहरण नहीं मिलता है:

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

अद्यतन (जावा 8 रिलीज के बाद):

मुझे (एलन) पहली बार इस उत्तर को पोस्ट किए कई साल हो गए हैं, और मुझे अभी भी विश्वास नहीं हो रहा है कि मैं इस उत्तर के लिए SO अंक एकत्र कर रहा हूं। किसी भी दर पर, अब जब जावा 8 ने भाषा के लिए क्लोजर पेश किया है, तो मेरा जवाब अब काफी अलग और सरल होगा। जावा 8 के साथ, एक अलग स्थिर उपयोगिता वर्ग की आवश्यकता नहीं है। इसलिए यदि आप उस 1 तत्व को ढूंढना चाहते हैं जो आपके विधेय से मेल खाता है।

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

Optionals के लिए JDK 8 एपीआई की क्षमता के लिए है get(), isPresent(), orElse(defaultUser), orElseGet(userSupplier)और orElseThrow(exceptionSupplier), साथ ही अन्य 'monadic' के रूप में इस तरह के कार्यों map, flatMapऔर filter

यदि आप बस उन सभी उपयोगकर्ताओं को इकट्ठा करना चाहते हैं जो विधेय से मेल खाते हैं, तो Collectorsवांछित संग्रह में स्ट्रीम को समाप्त करने के लिए उपयोग करें ।

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

जावा 8 स्ट्रीम कैसे काम करती है , इस बारे में अधिक उदाहरणों के लिए यहां देखें ।


27
हाँ, लेकिन मैं पहिया को फिर से, बार-बार मजबूत करने से नफरत करता हूं। मुझे कुछ उपयोगिता पुस्तकालय मिलेंगे जो मुझे चाहिए।
केविन वोंग

2
यदि आप नया संग्रह नहीं चाहते हैं तो यह सबसे अच्छा तरीका नहीं है। फ़िल्टर इट्रेटर रूपक का उपयोग करें, जो एक नए संग्रह में इनपुट कर सकता है, या यह वह सब हो सकता है जिसकी आपको आवश्यकता है।
जोश

@ नेस्टर: एक स्काला कॉम्प्रिहेंशन में, फ़िल्टर करना ज्यादा सरल होगा:val authorized = for (user <- users if user.isAuthorized) yield user
एलन

क्या यह मूल संग्रह को संशोधित करता है या एक नया निर्माण करता है? मैंने इस पद्धति का उपयोग करने की कोशिश की और मेरे दोनों संग्रह (मूल और विधि से लौटा हुआ) दोनों लॉग किए, वे समान हैं। @ एलन
रोहन

1
@ रोहन, यह मूल संग्रह को म्यूट करने के लिए नहीं है। ध्यान दें कि ऊपर दिया गया परिणाम संग्रह नवनिर्मित है, और फ़िल्टर विधि परिणाम संग्रह में तभी जोड़ता है जब विधेय लागू होता है।
एलन

92

Apache Commons से CollectionUtils.filter (Collection, Predicate) का उपयोग करें ।


3
यह ठीक है, लेकिन यह कोई सामान्य नहीं है, और संग्रह को अच्छी तरह से संशोधित करता है (अच्छा नहीं)
केविन वोंग

2
CollectionUtils में अन्य फ़िल्टर विधियाँ हैं जो मूल संग्रह को संशोधित नहीं करती हैं।
स्केफमैन

42
विशेष रूप से, विधि जो संग्रह को जगह में संशोधित नहीं करती है वह है org.apache.commons.collections.CollectionUtils # चयन (संग्रह, विधेय)
Eero

5
कॉमन्स कलेक्शंस v4 में अब यह जेनरिक का उपयोग करता है।
जस्टिन एमरी

1
इस विधि का उपयोग सावधानी के साथ किया जाना चाहिए क्योंकि यह निर्भर करता है (कम से कम कॉमन्स-कलेक्शन-3.2.1 के कार्यान्वयन में) itter.remove () विधि पर जो संग्रह के लिए वैकल्पिक है, इसलिए फ़िल्टर करने के बजाय, कहें, एक सरणी, आप हो सकता है एक UnsupportedOperationException प्राप्त करें।
user2417480

67

"सबसे अच्छा तरीका एक अनुरोध बहुत व्यापक है। क्या यह "सबसे छोटा" है? "सबसे तेज"? "पठनीय"? जगह में फ़िल्टर करें या किसी अन्य संग्रह में?

सबसे सरल (लेकिन सबसे अधिक पठनीय नहीं) तरीका इसे पुनरावृत्त करना और Iterator.remove () विधि का उपयोग करना है:

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

अब, इसे और अधिक पठनीय बनाने के लिए, आप इसे एक उपयोगिता विधि में लपेट सकते हैं। फिर एक IPredicate इंटरफ़ेस का आविष्कार करें, उस इंटरफ़ेस का एक अनाम कार्यान्वयन बनाएं और कुछ ऐसा करें:

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

जहां filterInPlace () संग्रह को पुनरावृत्त करता है और संग्रह में रखे जाने वाले उदाहरण को जानने के लिए Predicate.keepIt () कॉल करता है।

मैं वास्तव में इस कार्य के लिए केवल तृतीय-पक्ष लाइब्रेरी में लाने का औचित्य नहीं देखता।


6
मेरा वोट इसके लिए जाता है: यह सिर्फ काम करता है, जिसमें कोई बाहरी पुस्तकालय नहीं है। मैंने कभी महसूस नहीं किया कि एक Iterator को तुरंत बनाना प्रत्येक वाक्यविन्यास का उपयोग करने की तुलना में वास्तव में उपयोगी हो सकता है, या यह कि आप एक समवर्तीModificationException या ऐसा कुछ बिना सूची से आइटम निकाल सकते हैं। :)
ज़ीरो

1
मुझे लगता है कि नकल के बिना मानक जावा लिबास का उपयोग करना सबसे अच्छा तरीका है। 1.8 के लिए वहाँ stream()सुविधा होगी, लेकिन हर कोई नवीनतम खिलौनों के साथ खेलने के लिए नहीं जाता है: P
पॉपुलस

क्या यह मूल संग्रह को भी संशोधित करता है? @ZeroOne
रोहन

हां, यह करता है, @ रोहन। यदि आपको विश्वास नहीं है तो इसे आज़माएँ। ;)
जीरो ओने

हाहा मैंने किया! लेकिन मैं अपने मूल संग्रह को बनाए रखना चाहता हूं। क्या आप एक बाहरी देयता को जोड़े बिना ऐसा करने का एक तरीका सुझा सकते हैं? @ZeroOne
रोहन

62

अद्यतन संग्रह के लिए Google संग्रह पर विचार करें जो जेनरिक का समर्थन करता है।

अद्यतन : गूगल संग्रह पुस्तकालय अब पदावनत है। आपको इसके बजाय अमरूद के नवीनतम रिलीज का उपयोग करना चाहिए । यह अभी भी संग्रह ढांचे के लिए सभी समान एक्सटेंशन है जिसमें एक विधेय के आधार पर फ़िल्टरिंग के लिए एक तंत्र शामिल है।


हाँ, मुझे Google के संग्रह के बारे में पता था। जो संस्करण मैं उपयोग कर रहा था, उसमें कलेक्शन 2 नहीं था। मैंने इस प्रश्न का एक नया उत्तर जोड़ा है जो विशिष्ट पद्धति को सूचीबद्ध करता है।
केविन वोंग

7
केविन, Iterables.filter () और Iterators.filter () शुरू से वहाँ रहे हैं, और आमतौर पर आप सभी की जरूरत है।
केविन बोर्रिलियन

28

जावा 8 की प्रतीक्षा करें:

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
ऊँ ... यह तो क्रिया है। वे ऐसा क्यों नहीं कर सके: सूची <व्यक्ति> परिणाम = personList.filter (p -> p.age> 30);
केविन वोंग

8
सीधे कलेक्शन पर फ़िल्टर का उपयोग करने के लिए आपको removeIf कॉल का उपयोग करना होगा : download.java.net/jdk8/docs/api/java/util/…
gavenkoa

6
@ केविनवॉन्ग "वर्बोज़" बहुत सारी पूरी भाषा का वर्णन करता है जो मुझे लगता है। कम से कम वे सुसंगत हैं?
दुष्ट

5
क्यों नहीं पिछले भाग में कलेक्टर।
नेस्टर हर्नान्देज़ लोली

3
यहाँ एक लिंक gavenkoa प्रदान किया गया है जो 404 नहीं है personList.removeIf(p -> p.age < 30);। कम क्रिया । इसके अलावा, मैंने एप्स को लागू करने के लिए शुरू करने के बारे में सुना है जो स्वीकार करते हैं और Streamएस के बजाय एस वापस करते हैं Collectionक्योंकि Streamएस बहुत उपयोगी और तेज़ हैं लेकिन उनमें से / के लिए धीमी गति से जा रहा है।
कप्तान मैन

11

जावा 8 के शुरुआती रिलीज़ के बाद से, आप कुछ इस तरह की कोशिश कर सकते हैं:

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

उदाहरण के लिए, यदि आपके पास पूर्णांकों की एक सूची है और आप उन संख्याओं को फ़िल्टर करना चाहते हैं जो> 10 हैं और फिर उन संख्याओं को कंसोल पर प्रिंट करें, तो आप कुछ ऐसा कर सकते हैं:

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

11

मैं RxJava को रिंग में फेंक दूंगा , जो एंड्रॉइड पर भी उपलब्ध है । RxJava हमेशा सबसे अच्छा विकल्प नहीं हो सकता है, लेकिन यह आपको अधिक लचीलापन देगा यदि आप अपने संग्रह पर अधिक परिवर्तन जोड़ते हैं या फ़िल्टर करते समय त्रुटियों को संभालते हैं।

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);
        }
    });

आउटपुट:

1
3
5

RxJava के बारे में अधिक जानकारी यहांfilter पाई जा सकती है


7

स्थापित करना:

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();
    }
  }
}

उपयोगितायें:

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

2
ठीक है, लेकिन मैं एलन कार्यान्वयन को पसंद करता हूं क्योंकि आपको इसे बदलने के बजाय संग्रह की एक प्रति मिलती है। इसके अलावा, एलन का कोड थ्रेड सेफ है जबकि आपका नहीं है।
marcospereira

7

कैसे कुछ सादे और straighforward जावा के बारे में

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

सरल, पठनीय और आसान (और एंड्रॉइड में काम करता है!) लेकिन अगर आप जावा 8 का उपयोग कर रहे हैं, तो आप इसे एक मिठाई लाइन में कर सकते हैं:

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

ध्यान दें कि tolist () सांख्यिकीय रूप से आयात किया गया है



7

आइए देखें कि एक अंतर्निहित जेडडीके सूची और एक संग्रहणीय संग्रह का उपयोग करके एक MutableList को कैसे फ़िल्टर किया जाए

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

यदि आप 3 से कम संख्या को फ़िल्टर करना चाहते हैं, तो आप निम्न आउटपुट की अपेक्षा करेंगे।

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

यहां बताया गया है कि आप जावा 8 लैम्ब्डा का उपयोग करके कैसे फ़िल्टर कर सकते हैं 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));

यहां बताया गया है कि आप अनाम आंतरिक वर्ग का उपयोग करके कैसे फ़िल्टर कर सकते हैं 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));

यहाँ छानने JDK सूचियों और करने के लिए कुछ विकल्प हैं ग्रहण संग्रह MutableLists का उपयोग कर विधेय कारखाने।

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

यहां एक ऐसा संस्करण है जो Predicates2 कारखाने का उपयोग करने की selectWithविधि के बजाय , विधेय के लिए एक वस्तु आवंटित नहीं करता है Predicate2

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

कभी-कभी आप एक नकारात्मक स्थिति पर फ़िल्टर करना चाहते हैं। उस कहा जाता है के लिए ग्रहण संग्रह में एक विशेष विधि है reject

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

विधि partitionदो संग्रह लौटाएगी, जिनके द्वारा चयनित तत्वों को अस्वीकार कर दिया जाएगा 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());

नोट: मैं एक्लिप्स कलेक्शंस के लिए कमिट हूं।


1
आप removeIfएक सूची पर कैसे करेंगे या आदिम के लिए सेट करेंगे?
विवेक राव

निष्कासन के लिए एपीआई EC 9.1 में आदिम संग्रह में जोड़ा गया था। eclipse.org/collections/javadoc/9.1.0/org/eclipse/collections/…
डोनाल्ड रब

5

ForEach DSL के साथ आप लिख सकते हैं

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();

[, त्वरित, भूरा, लोमड़ी, कूदता है, अधिक, आलसी, कुत्ता] के संग्रह को देखते हुए, इसका परिणाम [त्वरित, भूरा, कूदता, अधिक, आलसी] होता है, अर्थात सभी तीन वर्णों से अधिक लंबे होते हैं।

ForEach DSL द्वारा समर्थित सभी पुनरावृति शैलियाँ हैं

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

अधिक जानकारी के लिए, कृपया https://www.iam.unibe.ch/scg/svn_repos/Sources/Inororach देखें


यह बहुत चालाक है! हालांकि एक अच्छा रूबी-ईश सिंटैक्स लागू करने के लिए बहुत सारे काम! नकारात्मक यह है कि आपका फ़िल्टर प्रथम श्रेणी का कार्य नहीं है और इसलिए इसका पुन: उपयोग नहीं किया जा सकता है। क्लोजर पर रोल ...
oxbow_lakes

अच्छी बात। लूप बॉडी को फिर से उपयोग करने का एक तरीका यह है कि लूप को एक विधि में फिर से दर्शाया जाए जो चयन क्वेरी को पैरामीटर के रूप में लेता है। हालांकि यह सुनिश्चित करने के लिए वास्तविक बंद के रूप में आसान और शक्तिशाली नहीं है।
अकुंन


5

चूंकि java 9 Collectors.filtering सक्षम है:

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

इस प्रकार फ़िल्टरिंग होना चाहिए:

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

उदाहरण:

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

3

यह, वास्तविक बंदियों की कमी के साथ संयुक्त, जावा के लिए मेरी सबसे बड़ी पकड़ है। ईमानदारी से, ऊपर वर्णित अधिकांश विधियाँ पढ़ने में बहुत आसान हैं और वास्तव में कुशल हैं; हालाँकि, .Net, एर्लैंग, आदि के साथ समय बिताने के बाद ... भाषा स्तर पर एकीकृत सूची बोध सब कुछ इतना साफ कर देता है। भाषा के स्तर पर परिवर्धन के बिना, जावा इस क्षेत्र में अन्य भाषाओं की तरह ही स्वच्छ नहीं रह सकती।

यदि प्रदर्शन बहुत बड़ी चिंता का विषय है, तो Google संग्रह जाने का तरीका है (या अपनी स्वयं की सरल उपयोगिता लिखना)। कुछ लोगों के लिए लैम्बज सिंटैक्स अधिक पठनीय है, लेकिन यह उतना कुशल नहीं है।

और फिर एक पुस्तकालय है जो मैंने लिखा था। मैं इसकी दक्षता (हाँ, इसके बुरे) के संबंध में किसी भी प्रश्न को अनदेखा करूँगा ...... हाँ, मैं इसके स्पष्ट प्रतिबिंब को जानता हूं, और नहीं मैं वास्तव में इसका उपयोग नहीं करता, लेकिन यह काम करता है:

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

या

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

संपर्क? भले ही आपकी लाइब्रेरी अक्षम हो या अन्यथा अनुपयोगी हो, यह देखने के लिए दिलचस्प हो सकता है कि स्रोत उपलब्ध है या नहीं।
MatrixFrog

रेपो को सार्वजनिक किया गया ( net-machine.com/indefero/p/jdclib/source/tree/master )। आप अभिव्यक्ति पैकेज में रुचि रखते हैं। उदाहरण के उपयोग के साथ परीक्षण पैकेज में एक परीक्षक है। मैंने कभी भी ऊपर संदर्भित स्ट्रिंग क्वेरी इंटरफ़ेस पर बहुत अधिक काम नहीं किया (एक वास्तविक पार्सर लिखने का मन नहीं था), इसलिए परीक्षक में स्पष्ट क्वेरी इंटरफ़ेस जाने का रास्ता है।
jdc0589

2

JFilter http://code.google.com/p/jfilter/ आपकी आवश्यकता के लिए सबसे उपयुक्त है।

JFilter जावा बीन्स के संग्रह के लिए एक सरल और उच्च प्रदर्शन वाला ओपन सोर्स लाइब्रेरी है।

प्रमुख विशेषताऐं

  • संग्रह का समर्थन (java.util.Collection, java.util.Map और Array) गुण।
  • किसी भी गहराई के संग्रह के अंदर संग्रह का समर्थन।
  • आंतरिक प्रश्नों का समर्थन।
  • पैरामीटर किए गए प्रश्नों का समर्थन।
  • कुछ 100 एमएस में 1 मिलियन रिकॉर्ड फ़िल्टर कर सकते हैं।
  • फ़िल्टर (क्वेरी) सरल json प्रारूप में दिया गया है, यह मैंगोडब प्रश्नों की तरह है। निम्नलिखित कुछ उदाहरण हैं।
  • {"id": {"$ le": "10"}
    • जहां ऑब्जेक्ट आईडी प्रॉपर्टी 10 से कम है।
  • {"id": {"$" में: ["0", "100"]}}
    • जहां ऑब्जेक्ट आईडी प्रॉपर्टी 0 या 100 है।
  • { "पंक्ति आइटम": { "lineAmount": "1"}}
    • जहां पैरामीटर के प्रकार की लाइन इट्स कलेक्शन प्रॉपर्टी में लाइनअमाउंट 1 के बराबर है।
  • {"$" और ": [{" id ":" 0 "}, {" बिलिंगअदालत ": {" शहर ":" DEL "}}]}
    • जहाँ id प्रॉपर्टी 0 है और बिलिंगएड्रेस.सिटी प्रॉपर्टी DEL है।
  • {"लाइन इटिम्स": {"टैक्स": {"कुंजी": {"कोड": "जीएसटी"}, "मूल्य": {"$ gt": "1.01"}}}}}
    • जहाँ लाइनमैट पैरामीटर प्रकार की संपत्ति का संग्रह करता है, जिसमें टैक्स मैप होता है, पैरामीटराइज़्ड प्रकार की संपत्ति का कोड 1.01 से अधिक जीएसटी मूल्य के बराबर होता है।
  • {[$ या ’: [{'कोड’:} 10 ’}, {' स्कस’: {and $ और ’: [{: मूल्य’: {’$ in’: ['20 ’,' 40’]} }, {'कोड': 'RedApple'}]}}]}
    • उन सभी उत्पादों का चयन करें जहां उत्पाद कोड 10 या 20 और 40 में sku मूल्य है और sku कोड "RedApple" है।

1
आपको यह बताना चाहिए कि आप लेखक हैं (जैसा कि मुझे लगता है कि यह मामला है)।
assylias

हां, मैं इस पुस्तकालय का लेखक हूं।
कामरान अली खान

2

मैंने एक विस्तारित Iterable वर्ग लिखा है जो संग्रह सामग्री की नकल के बिना कार्यात्मक एल्गोरिदम को लागू करने का समर्थन करता है।

उपयोग:

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);
}

उपरोक्त कोड वास्तव में निष्पादित होगा

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


2

कुछ वास्तव में महान महान जवाब यहाँ। मुझे, मैं जितना संभव हो उतना सरल और पठनीय रखना चाहूंगा:

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();
                }
            }
        }
    }
}

बस फ़िल्टर प्रति उचित बहिष्करण को लागू करें। कलेक्शन पर आपकी तरह ही अलग-अलग फ़िल्टर होने पर आप समाप्त हो जाएंगे ...
लॉरेंस

1

सरल पूर्व-जावा 8 समाधान:

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

दुर्भाग्य से यह समाधान पूरी तरह से सामान्य नहीं है, दिए गए संग्रह के प्रकार के बजाय एक सूची का उत्पादन। इसके अलावा, पुस्तकालयों या लेखन कार्यों में लाना, जो इस कोड को लपेटते हैं, मुझे लगता है कि हालत जटिल नहीं है, लेकिन तब आप शर्त के लिए एक फ़ंक्शन लिख सकते हैं।


1

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

विभिन्न संभावनाओं का समर्थन करता है,

संग्रह दिया गया,

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

प्रकार के,

class Dto
{
    private int id;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getText()
    {
        return text;
    }
}

फ़िल्टर

जावा 7

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

जावा 8

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

इसके अलावा,

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"});

सॉर्टिंग (जावा 7 के लिए भी उपलब्ध है)

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

समूहीकरण (जावा 7 के लिए भी उपलब्ध है)

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

जॉइन (जावा 7 के लिए भी उपलब्ध)

दिया हुआ,

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<>();

जैसे शामिल हो सकते हैं,

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();

भाव

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

1

मेरा उत्तर उस पर केविन वोंग से आता है, यहां वसंतCollectionUtils से एक-लाइनर और जावा 8 लैम्ब्डा अभिव्यक्ति का उपयोग किया जाता है।

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

यह उतना ही संक्षिप्त और पठनीय है जितना मैंने देखा है (पहलू-आधारित पुस्तकालयों का उपयोग किए बिना)

स्प्रिंग कलेक्शन Utils स्प्रिंग संस्करण 4.0.2 से उपलब्ध है। कृपया याद रखें, और आपको JDK 1.8 और भाषा स्तर 8+ की आवश्यकता है।


1

java 8विशेष रूप से उपयोग करना , lambda expressionआप इसे नीचे दिए गए उदाहरण की तरह कर सकते हैं:

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

जहां प्रत्येक संग्रह के productअंदर myProducts, यदि prod.price>10, तो इस उत्पाद को नई फ़िल्टर्ड सूची में जोड़ें।


1

मुझे सूची में पहले से मौजूद मूल्यों के आधार पर एक सूची को फ़िल्टर करने की आवश्यकता थी। उदाहरण के लिए, निम्नलिखित सभी मानों को हटा दें जो वर्तमान मूल्य से कम है। {२ ५ ३ ४} ५} -> {२ ५ 7}। या उदाहरण के लिए सभी डुप्लिकेट को हटाने के लिए {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;
    }
}

इस तरह मधुमक्खी का उपयोग किया जाएगा।

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

अमरूद के साथ:

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

जावा 8 में, आप सीधे इस फ़िल्टर विधि का उपयोग कर सकते हैं और फिर ऐसा कर सकते हैं।

 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); 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.