2016-03-23 43 views
6

में कॉन्सट के साथ ऑब्जेक्ट की विशिष्ट सूची कैसे प्राप्त करें मेरे पास 2 जावा क्लासेस हैं।जावा 8

class A { 
String name; 
List<B> numbers; 
} 

class B { 
Integer number; 
} 

मैं कक्षा ए के विशिष्ट प्राप्त करना चाहता हूं और इसमें बी की सूची को जोड़ना चाहता हूं।

उदा। मान लीजिए कि मेरे पास निम्न वस्तुओं के साथ एक सूची है।

List<A>{ 
name = "abc" 
List<B>{1,2} 

name= "xyz" 
List<B>{3,4} 

name = "abc" 
List<B>{3,5} 
} 

परिणाम होना चाहिए:

List<A>{ 
name = "abc" 
List<B>{1,2,3,5} 

name="xyz" 
List<B>{3,4} 
} 

किसी भी मदद की सराहना की जाएगी।

नोट: मैं जावा 8 स्ट्रीम का उपयोग करके इस कार्यक्षमता को प्राप्त करना चाहता हूं।

धन्यवाद

+0

@PaulBoddington हाँ मैं डेटाबेस से मूल्यों के साथ नई श्रेणी ए उदाहरण बना रहा हूं और इसे सूची में जोड़ रहा हूं। एक बार सूची आबादी हो जाती है। मुझे कक्षा बी –

+1

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

उत्तर

3

आप toMap कलेक्टर का उपयोग हो सकता है:,

Collection<A> result = list.stream() 
     .collect(Collectors.toMap(a -> a.name, a -> a, 
         (a, b) -> {a.numbers.addAll(b.numbers); return a;})) 
     .values(); 

आप List में उस के बाद परिणाम कॉपी कर सकते हैं (जैसे new ArrayList<>(result)), लेकिन जैसा कि हम किसी विशेष क्रम बनाए रखने के नहीं है होने List बहुत नहीं है उपयोगी। परिणामस्वरूप Collection वाले परिदृश्यों में से अधिकांश ठीक है।

+3

आप 'toMap()' के चार-तर्क अधिभार का उपयोग करके और 'प्रदायक' के रूप में 'LinkedHashMap :: new' को पारित करके आदेश को संरक्षित कर सकते हैं। – jaco0646

+0

मेरे लिए यह लाइन 39 पर 'java.lang.UnsupportedOperationException' देता है: http://pastebin.com/fAvd6jMi – ctomek

+0

@ctomek, आपकी सूचियां' Arrays.asList' के रूप में बनाई गई हैं जो नए तत्वों को जोड़ने का समर्थन नहीं करती हैं। इसके बजाय 'ArrayList' का उपयोग करके आसानी से तय किया जा सकता है। –

1

यहाँ मेरा उत्तर है। मैंने इसे थोड़ा आसान बनाने के लिए A के लिए एक कन्स्ट्रक्टर जोड़ा है।

public class Main { 

    static class A { 
     String name; 
     List<B> numbers; 

     A(String name, List<B> numbers) { 
      this.name = name; 
      this.numbers = new ArrayList<>(numbers); 
     } 
    } 

    static class B { 
     Integer number; 
    } 

    static List<A> merge(List<A> list) { 
     Map<String, List<B>> map = new LinkedHashMap<>(); 
     for (A a : list) 
      map.computeIfAbsent(a.name, k -> new ArrayList<>()).addAll(a.numbers); 
     return map.entrySet() 
        .stream() 
        .map(e -> new A(e.getKey(), e.getValue())) 
        .collect(Collectors.toList()); 
    } 
} 

वहाँ लगभग निश्चित रूप से कुछ शुरुआत list.stream()... पूरे विधि एक एक लाइनर बनाने के साथ merge विधि के पहले 3 लाइनों को बदलने के लिए एक आसान तरीका है। हालांकि मैं इसे काम करने में सक्षम नहीं था। शायद कोई और इस जवाब को संपादित कर सकता है कि कैसे?

2

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

List<A> merge(List<A> input) { 
    return input.stream() 
      .collect(groupingBy(a -> a.name)) // map created here 
      .entrySet() 
      .stream() 
      .map(entry -> new A(
        entry.getKey(), 
        entry.getValue().stream() 
          .flatMap(list -> list.numbers.stream()) 
          .collect(toList()) // merging behaviour 
      )).collect(toList()); 
} 

वहाँ मूल सूची की कोई उत्परिवर्तन है और आप आसानी से सूचियों विलय के व्यवहार को बदल सकते हैं - उदाहरण के लिए आप सिर्फ flatMap(list -> list.numbers.stream()) के बाद .distinct() जोड़ने (B को equals जोड़ने के बारे में याद है) या डुप्लिकेट से छुटकारा पाने के लिए करना चाहते हैं इसी तरह आप उन्हें .sorted() जोड़कर सॉर्ट कर सकते हैं (आपको बी को Comparable इंटरफ़ेस लागू करना होगा या बस .sorted(Comparator<B>) का उपयोग करना होगा)।

import org.junit.Test; 

import java.util.List; 

import static com.shazam.shazamcrest.MatcherAssert.assertThat; 
import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; 
import static java.util.Arrays.asList; 
import static java.util.stream.Collectors.groupingBy; 
import static java.util.stream.Collectors.toList; 

public class Main { 

    class A { 
     final String name; 
     final List<B> numbers; 
     A(String name, List<B> numbers) { 
      this.name = name; 
      this.numbers = numbers; 
     } 
    } 

    class B { 
     final Integer number; 
     B(Integer number) { 
      this.number = number; 
     } 
    } 

    List<A> merge(List<A> input) { 
     return input.stream() 
       .collect(groupingBy(a -> a.name)) 
       .entrySet() 
       .stream() 
       .map(entry -> new A(
         entry.getKey(), 
         entry.getValue().stream() 
           .flatMap(list -> list.numbers.stream()) 
           .collect(toList()) 
       )).collect(toList()); 
    } 

    @Test 
    public void test() { 
     List<A> input = asList(
       new A("abc", asList(new B(1), new B(2))), 
       new A("xyz", asList(new B(3), new B(4))), 
       new A("abc", asList(new B(3), new B(5))) 
     ); 

     List<A> list = merge(input); 

     assertThat(list, sameBeanAs(asList(
       new A("abc", asList(new B(1), new B(2), new B(3), new B(5))), 
       new A("xyz", asList(new B(3), new B(4))) 
     ))); 
    } 

} 

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

यहाँ परीक्षण और आयात के साथ पूर्ण कोड है

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

class A { 
    final String name; 
    final String type; 
    final List<B> numbers; 
    A(String name, String type, List<B> numbers) { 
     this.name = name; 
     this.type = type; 
     this.numbers = numbers; 
    } 
} 

class B { 
    final Integer number; 
    B(Integer number) { 
     this.number = number; 
    } 
} 

class Group { 
    final String name; 
    final String type; 
    Group(String name, String type) { 
     this.name = name; 
     this.type = type; 
    } 
    // this needs to have equals and hashCode methods as we use it as a key in a map 
} 

List<A> merge(List<A> input) { 
    return input.stream() 
      .collect(groupingBy(a -> new Group(a.name, a.type))) 
      .entrySet() 
      .stream() 
      .map(entry -> new A(
        entry.getKey().name, // entry.getKey() is now Group, not String 
        entry.getKey().type, 
        entry.getValue().get(0).numbers // no merging, just take first 
      )).collect(toList()); 
} 
+0

हाय, आपके उत्तर के लिए धन्यवाद। क्या मैं समूह में कई फ़ील्ड जोड़ सकता हूं? यदि हां तो वाक्यविन्यास क्या होगा? –

+0

क्या आपका समाधान काम करेगा यदि कक्षा ए में अधिक फ़ील्ड हैं लेकिन कथन द्वारा समूहबद्ध नहीं करना चाहिए? –