अमरूद: कोई लिस्टसेफ़िल्टर () फ़ंक्शन क्यों नहीं है?


86

वहाँ एक कारण है

Lists.transform()

लेकिन नहीं

Lists.filter()

?

मैं किसी सूची को सही तरीके से कैसे फ़िल्टर करूं? मैं प्रयोग कर सकता हूँ

new ArrayList(Collection2.filter())

बेशक, लेकिन इस तरह से यह गारंटी नहीं है कि मेरा आदेश वही रहता है, अगर मैं सही ढंग से समझता हूं।


8
FYI करें, List.newArrayList (Iterables.filter (...)) आम तौर पर नए ArrayList (Collection2.filter (...)) की तुलना में तेज़ है। ArrayList निर्माता फ़िल्टर किए गए संग्रह पर आकार () कहता है, और आकार की गणना करने के लिए आवश्यक है कि फ़िल्टर को मूल सूची के प्रत्येक तत्व पर लागू किया जाए।
जेरेड लेवी

4
@JaredLevy शायद इसके बजाय List.newArrayList(Iterables.filter(...)), यह कहना चाहिए Lists.newArrayList(Iterables.filter(...))
अब्दुल

जवाबों:


57

इसे लागू नहीं किया गया था क्योंकि यह एक खतरनाक बड़ी संख्या में धीमी विधियों को उजागर करेगा, जैसे कि रिटर्न सूची दृश्य (प्रदर्शन कीड़े को आमंत्रित करते हुए) पर #get (इंडेक्स)। और ListIterator के रूप में अच्छी तरह से लागू करने के लिए एक दर्द होगा (हालांकि मैंने उस कवर करने के लिए एक पैच साल पहले प्रस्तुत किया था)।

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


7
आप मान रहे हैं कि सूची दृश्य वापस आ जाएगा। हालाँकि #filter को एक नई भौतिक सूची को वापस करने के रूप में लागू किया जा सकता है, जो कि वास्तव में Iterable पर एक के विपरीत सूचियों के लिए एक फिल्टर विधि से मैं क्या उम्मीद करूंगा।
फेलिक्स लीपोल्ड

@FelixLeipold हालांकि यह पानी कीचड़ होगा। जैसा कि होता है, filterलगातार एक दृश्य का अर्थ है (व्यवहार के साथ-साथ इसका अर्थ है कि क्या है) Iterables.filter, Sets.filterआदि , चूंकि किसी भी पर Iterables.filterआसानी से संयोजित होता है , मुझे यह एक अच्छा डिज़ाइन ट्रेड-ऑफ (बनाम अतिरिक्त तरीकों और नामों के साथ, जैसे या whatnot) के साथ मिल रहा है , सरल उपयोगिताओं के संयोजन के लिए)। copyOfImmutableCollectionfilteredCopy
ल्यूक उशरवुड

37

आप उपयोग कर सकते हैं Iterables.filter, जो निश्चित रूप से आदेश बनाए रखेगा।

ध्यान दें कि एक नई सूची का निर्माण करके, आप तत्वों (सिर्फ संदर्भ, निश्चित रूप से) की नकल करेंगे - इसलिए यह मूल सूची पर एक लाइव दृश्य नहीं होगा। एक दृश्य बनाना बहुत मुश्किल होगा - इस स्थिति पर विचार करें:

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

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

(यह सिर्फ अनुमान लगा रहा है, तुम मन हो सकता है। हो सकता है कि अमरूद अनुरक्षकों में से एक वास्तविक कारण के साथ चिप जाएगा :)


1
Collections2.filter.iteratorबस कॉल करता है Iterables.filter, इसलिए परिणाम समान है।
स्कफमैन

@skaffman: जिस स्थिति में मैं Iterables.filterकेवल स्पष्टता के लिए संस्करण का उपयोग करूंगा ।
जॉन स्कीट

3
... जब तक आपको view.size()कोड में कहीं बाद की आवश्यकता न हो :)
Xaerxess

28

मैं new List(Collection2.filter())निश्चित रूप से उपयोग कर सकता हूं , लेकिन इस तरह से यह गारंटी नहीं है कि मेरा ऑर्डर समान है।

यह सच नहीं है। Collections2.filter()एक आलसी-मूल्यांकन किया गया कार्य है - यह वास्तव में आपके संग्रह को तब तक फ़िल्टर नहीं करता है जब तक कि आप फ़िल्टर किए गए संस्करण का उपयोग शुरू नहीं करते हैं। उदाहरण के लिए, यदि आप फ़िल्टर किए गए संस्करण पर पुनरावृत्ति करते हैं, तो फ़िल्टर किए गए तत्व आपके मूल संग्रह (शून्य से फ़िल्टर किए गए शून्य, स्पष्ट रूप से) के रूप में उसी क्रम में पुनरावृत्त से बाहर निकल जाएंगे।

शायद आप सोच रहे थे कि यह फ़िल्टरिंग को आगे बढ़ाता है, फिर परिणामों को एक अनियंत्रित, कुछ फॉर्म के अनऑर्डेड संग्रह में डंप करता है - जो आपको दिखाई नहीं देता है।

इसलिए यदि आप Collections2.filter()एक नई सूची में इनपुट के रूप में आउटपुट का उपयोग करते हैं , तो आपका मूल आदेश बरकरार रहेगा

स्थैतिक आयात (और Lists.newArrayListफ़ंक्शन) का उपयोग करते हुए , यह काफी सफल हो जाता है:

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

ध्यान दें कि जब Collections2.filterनहीं बेसब्री से पुनरावृति अंतर्निहित संग्रह से अधिक, होगा Lists.newArrayList होगा - यह संग्रह फ़िल्टर्ड के सभी तत्वों को निकालने और उन्हें एक नया में कॉपी कर देंगे ArrayList


यह अधिक पसंद है: List filteredList = newArrayList(filter(originalList, new Predicate<T>() { @Override public boolean apply(T input) { return (...); } }));या यानी। List filteredList = newArrayList(filter(originalList, Predicates.notNull()));
Xaerxess

@Xaerxess: उफ़, हाँ, विधेय भूल गया ... तय
skaffman

@Bozho: धन्यवाद ... मुझे बहुत समय लग गया :)
skaffman

12

जैसा कि जॉन ने उल्लेख किया है, आप उपयोग कर सकते हैं Iterables.filter(..)या Collections2.filter(..)यदि आपको लाइव दृश्य की आवश्यकता नहीं है तो आप उपयोग कर सकते हैं ImmutableList.copyOf(Iterables.filter(..))या Lists.newArrayList( Iterables.filter(..))हां ऑर्डर बनाए रखा जाएगा।

यदि आप वास्तव में क्यों भाग में रुचि रखते हैं , तो आप अधिक जानकारी के लिए https://github.com/google/guava/issues/505 पर जा सकते हैं ।


6

दूसरों द्वारा कही गई बातों को सारांशित करते हुए, आप आसानी से सूचियों को फ़िल्टर करने के लिए एक सामान्य आवरण बना सकते हैं:

public static <T> List<T> filter(Iterable<T> userLists, Predicate<T> predicate) {
    return Lists.newArrayList(Iterables.filter(userLists, predicate));
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.