2016-03-22 3 views
7

मैं जावा के लिए नेट से कोड का एक टुकड़ा पोर्टिंग रहा हूँ और एक परिदृश्य में जहाँ मैं धारा का उपयोग करने के मैप करने के लिए & को कम करना चाहता हूँ पर ठोकर खाई।जावा 8 धारा में शामिल होने और वापसी से अधिक मान

class Content 
{ 
    private String propA, propB, propC; 
    Content(String a, String b, String c) 
    { 
    propA = a; propB = b; propC = c; 
    } 
    public String getA() { return propA; } 
    public String getB() { return propB; } 
    public String getC() { return propC; } 
} 

List<Content> contentList = new ArrayList(); 
contentList.add(new Content("A1", "B1", "C1")); 
contentList.add(new Content("A2", "B2", "C2")); 
contentList.add(new Content("A3", "B3", "C3")); 

मैं एक समारोह है कि contentlist की सामग्री के माध्यम से धारा और परिणाम

content { propA = "A1, A2, A3", propB = "B1, B2, B3", propC = "C1, C2, C3" } 

के साथ एक कक्षा लौट जावा के लिए मैं काफी नया हूँ कर सकते हैं लिखने के लिए, ताकि आप कुछ कोड है कि अधिक से मिलता-जुलता हो सकता है चाहता हूँ की तरह जावा

+1

अच्छा समस्या वर्णन में उपयोग करें। लेकिन अब, आपने क्या प्रयास किया है? StackOverflow अन्य लोगों को आपके लिए कोड लिखने के लिए एक समुदाय नहीं है। इसके बजाय, आपको एक [mcve] पोस्ट करने की ज़रूरत है जो आपने कोशिश की थी, जो मिला, और जो आपने अपेक्षित था, और स्टैक ओवरफ्लो समुदाय यह निर्धारित करने में मदद कर सकता है कि आप कहां गलत हो गए हैं और समाधान बताते हैं। सुझाव के लिए – AJNeufeld

+0

@AJNeufeld धन्यवाद। यह पहली बार है कि मैं एसओ पर एक प्रश्न पोस्ट करने की कोशिश कर रहा हूं हालांकि इसे हर दिन इस्तेमाल करते हैं। मैं सामग्री को जोड़ने के लिए एक चर के साथ लूप के लिए बुनियादी के साथ काम कर रहा हूँ। और मैंने स्ट्रीम पर प्रत्येक के लिए उपयोग करने का प्रयास किया, फिर एहसास हुआ कि जावा अज्ञात फ़ंक्शन फ़ोरैच ब्लॉक के अंदर परिवर्तनीय संशोधित करने की अनुमति नहीं देते हैं। इसके अलावा मैंने एक पहुंच के लिए एक संग्रह लिखने पर विचार किया लेकिन महसूस किया कि यह या तो कुशल नहीं होगा। – Vedanth

उत्तर

3

से सी # आप में BinaryOperator के लिए उचित लैम्ब्डा का उपयोग कर सकते समारोह को कम।

Content c = contentList 
      .stream() 
      .reduce((t, u) -> new Content(
            t.getA() + ',' + u.getA(), 
            t.getB() + ',' + u.getB(), 
            t.getC() + ',' + u.getC()) 
        ).get(); 
+1

यह काम करता है, लेकिन यह कई अस्थायी 'सामग्री' ऑब्जेक्ट बनाता है। – AJNeufeld

+1

@AJNeufeld सहमत हुए, लेकिन यह अंतरिक्ष और समय के बीच पसंद है। – mks

+1

केवल 3 गुणों के साथ, मैं अपने कार्यान्वयन के लिए आंशिक हूं। लेकिन एक सामान्य मामले में - अधिक संपत्तियों, अधिक जटिल गुणों, निजी संपत्तियों, आदि के साथ - सबसे अच्छा हो सकता है '((टी, यू) -> नई सामग्री (टी, यू);' विलय को प्रतिनिधि 'Content' ऑब्जेक्ट स्वयं एक विशेष निर्माता के साथ, या वास्तव में 'ContentCollector' लिख रहा है जो जानकारी को कुशलता से जमा करता है। – AJNeufeld

4
static Content merge(List<Content> list) { 
    return new Content(
      list.stream().map(Content::getA).collect(Collectors.joining(", ")), 
      list.stream().map(Content::getB).collect(Collectors.joining(", ")), 
      list.stream().map(Content::getC).collect(Collectors.joining(", "))); 
} 

संपादित करें:

class Merge { 

    public static Collector<Content, ?, Content> collector() { 
     return Collector.of(Merge::new, Merge::accept, Merge::combiner, Merge::finisher); 
    } 

    private StringJoiner a = new StringJoiner(", "); 
    private StringJoiner b = new StringJoiner(", "); 
    private StringJoiner c = new StringJoiner(", "); 

    private void accept(Content content) { 
     a.add(content.getA()); 
     b.add(content.getB()); 
     c.add(content.getC()); 
    } 

    private Merge combiner(Merge second) { 
     a.merge(second.a); 
     b.merge(second.b); 
     c.merge(second.c); 
     return this; 
    } 

    private Content finisher() { 
     return new Content(a.toString(), b.toString(), c.toString()); 
    } 
} 

के रूप में प्रयुक्त:

Content merged = contentList.stream().collect(Merge.collector()); 
3

तो फेडरिको के इनलाइन कलेक्टर विस्तार करते हुए, यहाँ एक ठोस विलय सामग्री वस्तुओं के लिए समर्पित वर्ग है आप lis पर 3 गुना फिर से नहीं करना चाहते हैं टी, या बहुत अधिक Content मध्यवर्ती वस्तुओं को बनाने के लिए नहीं करना चाहते, तो आप अपने खुद कार्यान्वयन के साथ धारा इकट्ठा करने के लिए आवश्यकता होगी:

public static Content collectToContent(Stream<Content> stream) { 
    return stream.collect(
     Collector.of(
      () -> new StringBuilder[] { 
        new StringBuilder(), 
        new StringBuilder(), 
        new StringBuilder() }, 
      (StringBuilder[] arr, Content elem) -> { 
       arr[0].append(arr[0].length() == 0 ? 
         elem.getA() : 
         ", " + elem.getA()); 
       arr[1].append(arr[1].length() == 0 ? 
         elem.getB() : 
         ", " + elem.getB()); 
       arr[2].append(arr[2].length() == 0 ? 
         elem.getC() : 
         ", " + elem.getC()); 
      }, 
      (arr1, arr2) -> { 
       arr1[0].append(arr1[0].length() == 0 ? 
         arr2[0].toString() : 
         arr2[0].length() == 0 ? 
           "" : 
           ", " + arr2[0].toString()); 
       arr1[1].append(arr1[1].length() == 0 ? 
         arr2[1].toString() : 
         arr2[1].length() == 0 ? 
           "" : 
           ", " + arr2[1].toString()); 
       arr1[2].append(arr1[2].length() == 0 ? 
         arr2[2].toString() : 
         arr2[2].length() == 0 ? 
           "" : 
           ", " + arr2[2].toString()); 
       return arr1; 
      }, 
      arr -> new Content(
        arr[0].toString(), 
        arr[1].toString(), 
        arr[2].toString()))); 
} 

यह कलेक्टर पहले 3 खाली StringBuilder ऑब्जेक्ट की श्रृंखला पैदा करता है। फिर एक संचयक को परिभाषित करता है जो प्रत्येक Content तत्व की संपत्ति को StringBuilder पर जोड़ता है। फिर यह एक मर्ज फ़ंक्शन को परिभाषित करता है जिसका उपयोग केवल तब किया जाता है जब धारा समानांतर में संसाधित होती है, जो दो पहले संचित आंशिक परिणामों को विलीन करती है। अंत में, यह एक फिनिशर फ़ंक्शन को भी परिभाषित करता है जो StringBuilder ऑब्जेक्ट्स को Content के नए उदाहरण में बदलता है, जिसमें प्रत्येक चरण पिछले चरणों के संचित तारों से संबंधित है।

कृपया आगे संदर्भ के लिए Stream.collect() और Collector.of() javadocs देखें।

4

इस तरह के कार्यों से निपटने के लिए एक भी एक में कई लेनेवालों के परिणाम गठबंधन करने के लिए किया जाएगा सबसे सामान्य तरीके से।

jOOL लाइब्रेरी का उपयोग करना, आप निम्न हो सकता है:

Content content = 
    Seq.seq(contentList) 
     .collect(
     Collectors.mapping(Content::getA, Collectors.joining(", ")), 
     Collectors.mapping(Content::getB, Collectors.joining(", ")), 
     Collectors.mapping(Content::getC, Collectors.joining(", ")) 
     ).map(Content::new); 

इस इनपुट सूची में से एक Seq बनाता है और एक Tuple3 बनाने के लिए, जो केवल 3 मूल्यों के लिए एक धारक है 3 दिए गए कलेक्टरों को जोड़ती है। उन 3 मानों को तब Content में कन्स्ट्रक्टर new Content(a, b, c) का उपयोग करके मैप किया जाता है। कलेक्टर खुद को बस अपने a, b या c मूल्य में प्रत्येक Content मानचित्रण और एक साथ एक ", " द्वारा अलग-अलग परिणाम शामिल हो रहे हैं।


तीसरे पक्ष के मदद के बिना, हम इस तरह हमारे अपने combiner कलेक्टर बना सकते हैं (इस StreamExpairing कलेक्टर, जो 2 कलेक्टरों के लिए एक ही बात करता है के आधार पर किया जाता है)। यह 3 कलेक्टरों को तर्क के रूप में लेता है और 3 एकत्रित मूल्यों के परिणामस्वरूप एक फिनिशर ऑपरेशन करता है।

public interface TriFunction<T, U, V, R> { 
    R apply(T t, U u, V v); 
} 

public static <T, A1, A2, A3, R1, R2, R3, R> Collector<T, ?, R> combining(Collector<? super T, A1, R1> c1, Collector<? super T, A2, R2> c2, Collector<? super T, A3, R3> c3, TriFunction<? super R1, ? super R2, ? super R3, ? extends R> finisher) { 

    final class Box<A, B, C> { 
     A a; B b; C c; 
     Box(A a, B b, C c) { 
      this.a = a; 
      this.b = b; 
      this.c = c; 
     } 
    } 

    EnumSet<Characteristics> c = EnumSet.noneOf(Characteristics.class); 
    c.addAll(c1.characteristics()); 
    c.retainAll(c2.characteristics()); 
    c.retainAll(c3.characteristics()); 
    c.remove(Characteristics.IDENTITY_FINISH); 

    return Collector.of(
      () -> new Box<>(c1.supplier().get(), c2.supplier().get(), c3.supplier().get()), 
      (acc, v) -> { 
       c1.accumulator().accept(acc.a, v); 
       c2.accumulator().accept(acc.b, v); 
       c3.accumulator().accept(acc.c, v); 
      }, 
      (acc1, acc2) -> { 
       acc1.a = c1.combiner().apply(acc1.a, acc2.a); 
       acc1.b = c2.combiner().apply(acc1.b, acc2.b); 
       acc1.c = c3.combiner().apply(acc1.c, acc2.c); 
       return acc1; 
      }, 
      acc -> finisher.apply(c1.finisher().apply(acc.a), c2.finisher().apply(acc.b), c3.finisher().apply(acc.c)), 
      c.toArray(new Characteristics[c.size()]) 
      ); 
} 

और अंत के साथ

Content content = contentList.stream().collect(combining(
    Collectors.mapping(Content::getA, Collectors.joining(", ")), 
    Collectors.mapping(Content::getB, Collectors.joining(", ")), 
    Collectors.mapping(Content::getC, Collectors.joining(", ")), 
    Content::new 
)); 
संबंधित मुद्दे