2013-01-15 25 views
13

में एक सूची में पुनरावृत्त मेरे पास निम्न उदाहरण कोड है जिसमें 3-नेस्टेड फॉर-लूप शामिल हैं।अमरूद इटरेटर्स, और एक सूची ऑब्जेक्ट

for(Continent continent : continentList) 
{ 
    for(Country country : continent.getCountries()) 
    { 
     for(City city : country.getCities()) 
     { 
      //Do stuff with city objects 
     } 
    } 
} 

क्या गुवा और इटरेटर्स का उपयोग करके इस नेस्टेड फॉर-लूप की नकल करने का कोई तरीका है? मैं बहुत भाग्य के बिना एक उपयुक्त उदाहरण खोजने की कोशिश कर रहा हूं, और मैं सोच रहा था कि कोई मेरी मदद कर सकता है? फिल्टर का उपयोग करके मेरा एक सहकर्मी उल्लेख किया गया।

संपादित करें: उदाहरण के कोड

+3

आप अपने मैपिंग घोंसला कर सकते हैं। आईएमएचओ कम से कम बाहरी लूप के लिए नेस्टेड लूप के रूप में सरल होने की संभावना है। –

+3

लाइन 3 में, यह "continent.getCountries()" नहीं होना चाहिए? – Chris

+0

आप <महाद्वीप, देश, शहर> ट्रिपल की एक सूची बनाने के लिए गुवाओं "ट्रांसफॉर्म" और "कॉन्सैट" का उपयोग कर सकते हैं और फिर उस पर फिर से चालू हो सकते हैं, लेकिन जावा 7 के साथ कम से कम, कोड बदसूरत होगा। मैं नेस्टेड लूप के साथ रहूँगा। – Chris

उत्तर

2

नहीं में फिक्स्ड छोटे बग, वहाँ एक आसान तरीका नहीं है। इसके अलावा, यह आपके प्रश्न में प्रत्येक लूप के लिए अधिक verbose होगा।

http://code.google.com/p/guava-libraries/issues/detail?id=218#c5 देखें और http://code.google.com/p/guava-libraries/wiki/FunctionalExplained

11

पीटर Lawrey टिप्पणी की में चेतावनियां, इस लगभग निश्चित रूप से नेस्ट छोरों के रूप में सरल होने जा रहा है।

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

अधिक से अधिक, Guava documentation यह चेतावनी देता है
  • कार्यात्मक मुहावरों का उपयोग आपकी संपूर्ण परियोजना के लिए कोड की लाइनों की शुद्ध बचत के परिणामस्वरूप होगा। फ़ंक्शन के किसी अन्य फ़ाइल, या निरंतर परिभाषा को स्थानांतरित करने में मदद नहीं करता है।
  • दक्षता के लिए, आपको संग्रह के आलसी गणना के दृश्य की आवश्यकता है और स्पष्ट रूप से गणना किए गए संग्रह के लिए व्यवस्थित नहीं हो सकता है। इसके अतिरिक्त, आपने उन निर्देशों का पालन करने के अलावा प्रभावी जावा, आइटम 55, और पढ़ और पढ़ा है, आपने वास्तव में बेंचमार्किंग किया है यह साबित करने के लिए कि यह संस्करण तेज़ है, और इसे साबित करने के लिए संख्या उद्धृत कर सकते हैं।

कृपया सुनिश्चित करें कि, जब अमरूद के कार्यात्मक उपयोगिताओं का उपयोग कर, काम करने के पारंपरिक जरूरी रास्ता अधिक पढ़ने योग्य नहीं है कि हो सकता है। इसे लिखने का प्रयास करें। क्या वह इतना बुरा था? क्या पूर्वोत्तर अजीब कार्यात्मक दृष्टिकोण से पठनीय था, आप कोशिश करने के बारे में थे?

हालांकि, अगर आप सलाह की अनदेखी पर आग्रहपूर्ण कर रहे हैं, आप कुछ इस कुरूपता की तरह इस्तेमाल कर सकते हैं (ध्यान दें मैं वास्तव में संकलन या इस चलाने के लिए प्रयास नहीं किया है):

FluentIterable.from(continentList) 
    .transform(new Function<Continent, Void>() { 
     public Void apply(Continent continent) { 
      return FluentIterable.from(continent.getCountries()) 
       .transform(new Function<Country, Void>() { 
        public Void apply(Country country) { 
         return FluentIterable.from(country.getCities()) 
          .transform(new Function<City, Void>() { 
           public Void apply(City city) { 
            // do stuff with city object 
            return null; 
           } 
          }); 
        } 
       }); 
     } 
    }); 

अब अपने आप से पूछना: आप कौन सा बनाए रखना चाहते हैं? कौन सबसे कुशल होने जा रहा है?

अमरूद के कार्यात्मक मुहावरे के लिए वैध उपयोग-मामले हैं। लूप के लिए जावा को प्रतिस्थापित करना, लूप के लिए भी घोंसला, उनमें से एक नहीं है।

+4

['FluentIterable.transformAndConcat()'] (http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/FluentIterable.html) का उपयोग करके, आप इसके बजाय परिवर्तनों को चेन कर सकते हैं हालांकि, उन्हें घोंसला। –

+0

@ फ्रैंकपावेजौ: सच। लेकिन अगर यह थोड़ा क्लीनर होने जा रहा है, तो भी यह घोंसला वाले लूप की तुलना में कमजोर और कम पठनीय होगा। – ig0774

+0

@ ig0774 प्रो-टिप के लिए धन्यवाद :) – GobiasKoffi

3

एक और कुरूपता, AbstractIterator का उपयोग कर:

class CityIterable implements Iterable<City> { 
     List<Continent> continents; 

     CityIterable(List<Continent> continents) { 
      this.continents = continents; 
     } 

     @Override 
     public Iterator<City> iterator() { 
      return new AbstractIterator<City>() { 
       Iterator<Continent> continentIterator = continents.iterator(); 
       Iterator<Country> countryIterator; 
       Iterator<City> cityIterator; 

       @Override 
       protected City computeNext() { 
        if (cityIterator != null && cityIterator.hasNext()) { 
         return cityIterator.next(); 
        } 
        if (countryIterator != null && countryIterator.hasNext()) { 
         cityIterator = countryIterator.next().getCities().iterator(); 
         return computeNext(); 
        } 
        if (continentIterator.hasNext()) { 
         countryIterator = continentIterator.next().getCountries().iterator(); 
         return computeNext(); 
        } 
        return endOfData(); 
       } 
      }; 
     } 
    } 

तो यह बुला:

for (City city: new CityIterable(continentList)) { 
     System.out.println(city.name); 
    } 

देखते हुए कि यह कैसे monstruosity, ig0774 की सलाह का पालन करें और नेस्टेड छोरों रहते हैं।

पीएस फिल्टर के लिए कोई ज़रूरत नहीं है।

+0

प्रो-टिप के लिए धन्यवाद :) – GobiasKoffi

1

मैं दूसरों से सहमत हूं कि नेस्टेड लूप जाने का सबसे प्रभावी तरीका है। हालांकि: मैं एक अलग विधि करने के लिए प्रत्येक लूप स्तर निकालने दोनों पठनीयता बनाए रखने के लिए चाहते हैं और सुनिश्चित करें कि प्रत्येक विधि वास्तव में एक बात करता है:

public void doStuffWithWorld(World world){ 
    for (Continent continent : world.getContinents()) { 
     doStuffWithContinent(continent); 
    } 
} 

private void doStuffWithContinent(Continent continent) { 
    for (Country country : continent.getCountries()) { 
     doStuffWithCountry(country); 
    } 
} 

private void doStuffWithCountry(Country country) { 
    for(City city : country.getCities()){ 
     doStuffWithCity(city); 
    } 
} 

private void doStuffWithCity(City city) { 
    // do stuff here 
} 

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

+0

मुझे वास्तव में आपका सुझाव पसंद है; यदि आवश्यकता हो तो यह प्रत्येक व्यक्तिगत लूपर फ़ंक्शन का परीक्षण करने के लिए भी मुझे यूनिट करेगा। धन्यवाद :) – GobiasKoffi

8

आप के लिए स्थिर कार्यों को परिभाषित कर सकते हैं:
• getCountries() महाद्वीप, महाद्वीपों में या कार्य
• getCities() देश, देश में या कार्य

अब तुम कुछ की तरह कर सकते हैं ...

FluentIterable.from(continentList) 
    .transformAndConcat(Continent.getCountriesFunction()) 
    .transformAndConcat(Country.getCitiesFunction()) 
    . //filter //tranform //find //toList() //etc. 

हैं:
• आप की तरह इस (अधिक) अमरूद का उपयोग अक्सर।
• और कुछ नियम/विचार हैं जहां आप अपने कार्यों और भविष्यवाणियों को परिभाषित करते हैं।
• और फ़िल्टर करने या खोजने के लिए अलग-अलग (जटिल) चीजें हैं।
फिर यह एक महान वरदान हो सकता है और कई स्थितियों को काफी आसान बना सकता है। मुझे पता है मुझे खुशी है कि मैंने किया था।

यदि आप इसे कम इस्तेमाल करते हैं, तो मुझे @ लुइस वासरमैन से सहमत होना होगा। फिर यह परेशानी के लायक नहीं है। इसके अलावा, अन्य उदाहरणों की तरह अज्ञात आंतरिक वर्ग के रूप में कार्यों और भविष्यवाणियों को परिभाषित करना ... वास्तव में बदसूरत है।