2016-03-10 36 views
7

में तत्व मैं निम्नलिखित वर्ग है खोजने के लिए:जावा 8 स्ट्रीम सूची

public class Item { 
    int id; 
    String name; 
    // few other fields, contructor, getters and setters 
} 

मैं आइटम की एक सूची है। मैं सूची के माध्यम से पुन: प्रयास करना चाहता हूं और उस उदाहरण को ढूंढना चाहता हूं जिसमें एक विशेष आईडी है। मैं धाराओं के माध्यम से ऐसा करने की कोशिश कर रहा हूँ।

public void foobar() { 

    List<Item> items = getItemList(); 
    List<Integer> ids = getIdsToLookup(); 
    int id, i = ids.size() - 1; 

    while (i >= 0) { 
     id = ids.get(i); 
     Optional<Item> item = items 
      .stream() 
      .filter(a -> a.getId() == id) 
      .findFirst(); 
     // do stuff 
     i--; 
    } 
} 

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

ids.forEach(id -> 
    list.stream() 
    .filter(p -> p.getId() == id) 
    .findFirst() 
    .ifPresent(p -> {//do stuff here}); 
); 

यहाँ वैकल्पिक दिखाता है कि आपके फिल्टर विधि एक खाली धारा लौट सकते हैं, इसलिए यदि आप findFirst फोन यह एक या शून्य तत्वों पा सकते हैं:

+1

आप सूची में इंडेक्स के लिए और लैम्बडा में वर्तमान आइटम के लिए एक ही वैरिएबल का उपयोग कर रहे हैं। एक अलग नाम चुनें। वह कोड ठीक है, लेकिन काफी अक्षम है। यदि आपके पास एकाधिक आईडी हैं और सभी के लिए संबंधित आइटम ढूंढने की आवश्यकता है, तो हैश मैप <इंटीजर, आइटम> बनाकर शुरू करें और फिर हैश मैप का उपयोग करें। –

+0

मैं अपने कोड में एक अलग चर का उपयोग कर रहा हूं, मैं यहां कोड को सरल बनाने की कोशिश कर रहा था। मैं इसे बदल दूंगा। –

+1

परिवर्तनीय 'id' ** अंदर ** लूप को घोषित करें, और यह प्रभावी रूप से अंतिम होगा। बाहर होने के कारण, आप इसे प्रत्येक पुनरावृत्ति पर पुन: प्रारंभ करते हैं, और यह अंतिम नहीं है। सबसे छोटे दायरे में चर घोषित करना सामान्य रूप से एक सर्वोत्तम अभ्यास है। –

उत्तर

5

आप आईडी खोज करने के लिए की बहुत सारी है, तो यह एक समाधान है जो नहीं बल्कि प्रत्येक आईडी के लिए एक रेखीय खोज करने की तुलना में एक भी पास में यह होता है उपयोग करने के लिए अनुशंसा की जाती है आईडी सूची से बाहर, प्रत्येक खोज आईडी को खाली Optional पर मैप करना।

forEach का उपयोग कर से अधिक आइटम और प्रत्येक आइटम के लिए दूसरा बयान दोहराता है, यह जाँच करता है वहाँ एक खाली Optional के लिए अपने आईडी से एक मानचित्रण है और अगर इस तरह के एक मानचित्रण है एक Optional से बदलने के लिए, आइटम encapsulating करेंगे कि क्या, सभी एक ऑपरेशन में, computeIfPresent

पीछे की ओर ids सूची अंतिम ओवर for पाश दोहराता, तो आप उन्हें इसी क्रम में संसाधित करने और अगर वहाँ एक गैर खाली Optional है कार्रवाई करने के लिए कामना की है। के बाद से नक्शा सभी आईडी सूची में पाया के साथ प्रारंभ किया गया था, getnull वापस कभी नहीं जाएगा, यह एक खाली Optional वापस आ जाएगी, अगर आईडी items सूची में नहीं मिला था।

इस तरह, यह सोचते हैं Map के देखने O(1) समय जटिलता है, जो ठेठ कार्यान्वयन के मामले में है कि शुद्ध समय जटिलता O(m×n) से O(m+n) करने के लिए बदल ...

+0

मुझे एक ही पास करने और सभी आवश्यक प्रविष्टियां प्राप्त करने का विचार पसंद है। लेकिन मुझे उन प्रविष्टियों को संसाधित करने की आवश्यकता है जिन्हें मैंने उन्हें आईडी सूची में प्राप्त किया था। मुझे नहीं लगता कि उपरोक्त कोड ऑर्डर करने की परवाह करता है, है ना? साथ ही, क्या आप उपर्युक्त कोड में क्या करने का प्रयास कर रहे हैं, इसके बारे में कुछ स्पष्टीकरण दे सकते हैं? यह सहायक होगा। धन्यवाद। –

+0

@ गेंगीस खान: यह वही करता है जो आप चाहते हैं। 'For' लूप' ids' सूची के पीछे पीछे की तरफ इशारा कर रहा है जैसा आप चाहते थे। – Holger

8

आप कुछ इस तरह उपयोग कर सकते हैं।

+0

'findAny()' के साथ 'findFirst() 'को बदलकर प्रदर्शन में सुधार होगा। https://stackoverflow.com/questions/35359112/difference-between-findany-and-findfirst-in-java-8 – stuart

2

आप धाराओं के साथ चिपके रहते हैं और पीछे की ओर पुनरावृति करना चाहते हैं, तो आप इसे इस तरह कर सकता है:

IntStream.iterate(ids.size() - 1, i -> i - 1) 
    .limit(ids.size()) 
    .map(ids::get) // or .map(i -> ids.get(i)) 
    .forEach(id -> items.stream() 
     .filter(item -> item.getId() == id) 
     .findFirst().ifPresent(item -> { 
      // do stuff 
     })); 

इस कोड को तुम्हारा के रूप में ही है।

यह बीज के साथ शुरू होने से पीछे की ओर इशारा करता है: ids.size() - 1int रों की प्रारंभिक धारा, limit() साथ अपने आकार में सीमित है ताकि कोई नकारात्मक int रों देखते हैं और धारा ids की सूची के रूप में एक ही आकार है। फिर, एक map() आपरेशन वास्तविक idids सूची में ith की स्थिति में है कि करने के लिए सूचकांक (इस ids.get(i) लागू के माध्यम से किया जाता है) बदल देता है। अंत में, आइटम को items में आपके कोड में उसी तरह सूचीबद्ध किया गया है।

Map<Integer,Optional<Item>> map=ids.stream() 
    .collect(Collectors.toMap(id -> id, id -> Optional.empty())); 
items.forEach(item -> 
    map.computeIfPresent(item.getId(), (i,o)->o.isPresent()? o: Optional.of(item))); 
for(ListIterator<Integer> it=ids.listIterator(ids.size()); it.hasPrevious();) { 
    map.get(it.previous()).ifPresent(item -> { 
     // do stuff 
    }); 
} 

पहले बयान सिर्फ एक नक्शा बनाने:

+2

स्ट्रीम ऑपरेशन का मतलब है 'ओ (एन)' जटिलता वैसे भी ... – Holger

+0

@ होल्गर मेरा मतलब है 'आईडी' 'सूची –

+1

@ होल्गर अब मैं देखता हूं कि आपका क्या मतलब है, उस नोट को हटाने के लिए संपादित किया जाएगा। धन्यवाद! –

0

आप के लिए से ज़्यादा एक आइटम लगाना चाहते हैं प्रत्येक दिए गए आईडी और पाए गए आइटम के साथ कुछ करें, है ना? थोड़ा और प्रदर्शन सुधार:

Set<Integer> idsToLookup = new HashSet<>(getIdsToLookup()); // replace list with Set 
items.stream().filter(e -> idsToLookup.remove(e.getId())).forEach(/* doing something */); 
संबंधित मुद्दे