2011-08-26 15 views
19

सूचियों या इटेरबल्स को गुवा filter(Iterable<?> unfiltered, Class<T> type) का उपयोग करके आसानी से फ़िल्टर किया जा सकता है। यह कार्रवाई दो कार्य करता है: सूची फ़िल्टर किया जाता है और दिए गए प्रकार टी के अनुक्रम में रखता तब्दीलजेनेरिक प्रकारों की फ़िल्टरिंग सूचियां

अक्सर हालांकि मैं Iterables<Something<?>> साथ खत्म हो और मैं कुछ विशेष टी के लिए Iterables<Something<T>> की किसी परिणाम प्राप्त करना चाहते हैं

यह स्पष्ट है, कि अमरूद प्रकार विलोपन की वजह से बॉक्स से बाहर इस समस्या को हल नहीं कर सकते हैं: Something<T> अपने टी के बारे में किसी भी प्रत्यक्ष जानकारी प्रदान नहीं करता

चलें कहते हैं कि मैं S<? extends Number> की तरह कुछ है। अगर मैं कुछ विधेय जो मुझसे कहता है कि अगर S<?>S<Double> लिए casted किया जा सकता है मैं एक filer के रूप में उपयोग कर सकते हैं परिभाषित करने में सक्षम हूँ:

<T extends Number> Predicate<S<?>> isOfType(Class<N> type) {...} 

साथ:

Iterable<S<?>> numbers; 
Iterable<S<?>> filtered = Iterable.filter(numbers, isOfType(Double.class)); 

फ़िल्टर का कार्य करता है, लेकिन यह परिवर्तन कदम याद करता है। अगर मैं अपने विधेय अच्छी तरह से काम करता है लगता है कि मैं भी कास्टिंग के बारे में सोच सकता है:

Iterable<S<Double>> doubles = (Iterable<S<Double>>) filtered; 

लेकिन यह कुछ बदसूरत डाली आपरेशन उजागर करता है।

एक विकल्प के रूप में मैं कास्ट करने के लिए Function<S<?>, S<Double>> प्रदान कर सकता हूं। Class.cast() पर कॉन्सस्ट्रास्ट में हालांकि इसे ClassCastException फेंकना नहीं चाहिए, लेकिन तत्व को जाली (या परिवर्तित) नहीं किया जा सकता है, लेकिन बस null लौटाएं। इस तरह अनुक्रम किसी भी स्पष्ट कलाकारों के बिना परिवर्तित किया जा सकता है:

<T extends Number> Function<S<?>, S<T>> castOrNull(Class<N> type) {...} 

Iterable<S<Double>> doubles = Iterable.filter(numbers, castOrNull(Double.class)); 

लेकिन सूची वास्तव में फिल्टर नहीं किया जाता है: के बजाय यह अभी भी प्रत्येक तत्व जो परिवर्तित या casted नहीं कर सका S<Double> करने के लिए अशक्त ऑब्जेक्ट सम्मिलित हैं। लेकिन इस तरह एक अतिरिक्त छानने कदम से आसानी से हल हो सकता है:

Iterable<S<Double>> doubles = Iterables.filter(doubles, Predicates.notNull()); 

दूसरा समाधान ज्यादा मेरे लिए होशियार लगता है। परिभाषित करने के लिए Function या तो एक कास्ट (जो अनचेक ऑपरेशन छुपाता है) कर सकता है या यदि आवश्यक हो तो यह वास्तव में कुछ नया ऑब्जेक्ट S<T> बना सकता है।

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

<I,O> Iterables<O> convert(
    Iterables<O> input, 
    Function<? super I, ? extends O> convert, 
    Predicate<? super O> filter); 

<I,O> Iterables<O> convert(
    Iterables<O> input, 
    Function<? super I, ? extends O> convert); 

कहाँ दूसरा समारोह एक Predicates.notNull() के साथ पहली बार एक की एक छोटी सी में कटौती है,

लेकिन यह पहला कार्य भी है, क्योंकि अनुमान आवश्यक नहीं है Predicates.notNull()

कल्पना करें Iterable<Iterable<? extends Number>>। कनवर्टर फ़ंक्शन Function<Iterable<? extends Number>, Iterable<Double>> बस एक फ़िल्टर किए गए अनुक्रम को वापस कर सकता है जो शून्य को वापस करने के बजाय खाली हो सकता है। अतिरिक्त फ़िल्टर Iterables.isEmpty() का उपयोग कर खाली दृश्यों को अंततः छोड़ सकता है।

+1

यह उपयोगी होगा अगर 'Iterable.filter (...) 'विस्तारित कार्यक्षमता के साथ एक पुनरावर्तनीय लौटाता है ताकि आप श्रृंखला फ़िल्टर कर सकें। '/ * एस संग्रह */Iterable > युगल = Iterable.filter (संख्याओं, castOrNull (Double.class)) फ़िल्टर। (Predicates.notNull()) फ़िल्टर (Predicates.notEmpty());' – aalku

+4

आप क्यों इसे एक ही चरण में करना चाहते हैं? परिवर्तन और फ़िल्टरिंग अलग-अलग ऑपरेशन हैं। – pawstrong

उत्तर

2

अपने संग्रह ढांचे में स्कैला भाषा गुवा को समान कार्यक्षमता प्रदान करती है। हमारे पास विकल्प [टी] वर्ग है जिसे सबसे अधिक-तत्व-संग्रह के रूप में माना जा सकता है। सरल फ़िल्टरिंग या परिवर्तन विधियों में से एक तरीका है जो दोनों परिचालनों को एक साथ करता है। यह विकल्प वर्ग के मूल्य को वापस करने के लिए प्रदान किया गया परिवर्तन फ़ंक्शन प्रदान करता है। फिर यह संग्रहित ऑब्जेक्ट ऑब्जेक्ट्स की सामग्री को संग्रह में विलीन करता है। मुझे लगता है कि आप जावा में समान कार्यक्षमता को कार्यान्वित कर सकते हैं।

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

3

इस समस्या का monadic दृष्टिकोण, एक परिवर्तन समारोह है कि प्रकार T का एक उद्देश्य के लिए, प्रकार Iterable<T> की एक वस्तु रिटर्न को परिभाषित करते हुए एक ऑपरेशन iterables का एक iterable में एक iterable बदल देती है परिभाषित करने के लिए है। फिर आप प्रत्येक एक बार फिर से बनाने के लिए एकजुट हो सकते हैं। एक संयोजन के बाद मैपिंग के इस संयोजन को हास्केल में concatMap और स्कैला में flatMap कहा जाता है, और मुझे यकीन है कि इसमें अन्य नाम हैं।

इसे लागू करने के लिए, हम पहले एक ऐसा फ़ंक्शन बनाते हैं जो आपके S<? extends Number> को Iterable<S<Double>> में बदल देता है। यह आपके मौजूदा फ़ंक्शन के समान ही है, लेकिन हमारा सफलता केस एक का एक पुनरावृत्ति है, जिसमें हमारे S हैं, और विफलता केस (हमारा शून्य राज्य) एक खाली पुनरावर्तनीय है।

<T extends Number> Function<S<?>, Iterable<S<T>>> castOrNull(Class<T> type) { 
    return new Function<S<?>, Iterable<S<T>>> { 
     @Override 
     public Iterable<S<T>> apply(S<?> s) { 
      Object contained = s.get(); 
      if (!(contained instanceof T)) { 
       return ImmutableSet.of(); 
      } 

      return ImmutableSet.of(new S<T>(contained)); 
     } 
    }; 
} 

हम उपरोक्त निर्दिष्ट करते समय इसे मूल पुनरावर्तनीय पर लागू करते हैं।

Iterable<Iterable<S<Double>>> doubleIterables = Iterables.map(numbers, castOrNull(Double.class)); 

हम तो एक iterable फिर से निर्माण करने के लिए है, जो और उन्हें जो हमारे निकालना चाहते हैं के वांछित सभी मान कोई भी नहीं है एक साथ इन सभी को श्रेणीबद्ध कर सकते हैं।

Iterable<S<Double>> doubles = Iterables.concat(doubleIterables); 

अस्वीकरण: मैं इस संकलन प्रयास नहीं किया है। इसे काम करने के लिए आपको जेनेरिक के साथ खेलना पड़ सकता है।

+1

फ़ंक्शन को वापस करने के बाद शून्य या एक तत्व युक्त एक इटरबल एक बहुत ही रोचक दृष्टिकोण है। मैंने इस बारे में सोचा नहीं था, और मुझे लगता है कि यह बहुत अच्छा है कि यदि आवश्यक हो तो यह आपके फ़ंक्शन को शून्य कर देता है। चूंकि गुवा वैकल्पिक प्रकार को आर 10 (http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Optional.html) में जोड़ता है, मुझे आश्चर्य है कि क्या हम एक फ़ंक्शन का उपयोग कर सकते हैं, वैकल्पिक >> इसके बजाय, परिणामस्वरूप Iterable को "वर्तमान" मानों के लिए फ़िल्टर करना। –

+1

मैंने अभी लकीजाका के जवाब को पढ़ा है, और ऐसा लगता है कि वे फ्लैटमैप फ़ंक्शन के अतिरिक्त लाभ के साथ "विकल्प" प्रकार का उपयोग करके स्कैला में उपयोग करते हैं। अधिक जानकारी के लिए यह SO उत्तर देखें: http://stackoverflow.com/questions/1059776/scala-iterablemap-vs-iterableflatmap/1060400#1060400 "' flatMap' 'सूची [विकल्प [ए]]' सूची में बदल जाता है [ ए] ', किसी भी' विकल्प 'के साथ जो' कोई नहीं 'तक ड्रिल करता है, हटा दिया जाता है "। बहुत अच्छा। –

+2

@eneveu: यह अच्छा होगा अगर 'वैकल्पिक' लागू 'Iterable', लेकिन जहां तक ​​मुझे पता है कि इसे बनाने की कोई योजना नहीं है। हालांकि, जावा में संभवतः नैट प्राइस का कार्यान्वयन (https://github.com/npryce/maybe-java) करता है।कंपनी के एक लड़के के लिए मैंने काम किया है और इसे कुछ हद तक सुधार लिया है- आप उस संस्करण को https://github.com/youdevise/maybe-java पर देख सकते हैं। –

संबंधित मुद्दे