तत्वों के कई संग्रह को संयोजित करने का सुरुचिपूर्ण तरीका?


94

मान लें कि मेरे पास संग्रह की एक मनमानी संख्या है, प्रत्येक में उसी प्रकार की वस्तुएं हैं (उदाहरण के लिए, List<int> fooऔर List<int> bar)। यदि ये संग्रह स्वयं एक संग्रह में थे (उदाहरण के लिए List<List<int>>, मैं SelectManyइन सभी को एक संग्रह में संयोजित करने के लिए उपयोग कर सकता हूं ।

हालाँकि, अगर ये संग्रह पहले से ही समान संग्रह में नहीं हैं, तो यह मेरी धारणा है कि मुझे इस तरह की एक विधि लिखनी होगी:

public static IEnumerable<T> Combine<T>(params ICollection<T>[] toCombine)
{
   return toCombine.SelectMany(x => x);
}

जो मैं फिर इस तरह से कॉल करूंगा:

var combined = Combine(foo, bar);

क्या Combineऊपर की तरह एक उपयोगिता विधि लिखने के बिना (किसी भी संख्या में) संग्रहों को संयोजित करने का एक स्वच्छ, सुरुचिपूर्ण तरीका है ? यह काफी सरल लगता है कि LINQ में इसे करने का एक तरीका होना चाहिए, लेकिन शायद नहीं।



बहुत बड़ी संख्या में गणना करने वालों के लिए कॉनैट से सावधान रहें, आपके ढेर को उड़ा सकता है: programmaticallyspeaking.com/…
nawfal

जवाबों:


107

मुझे लगता है कि आप LINQ की तलाश कर रहे होंगे .Concat()?

var combined = foo.Concat(bar).Concat(foobar).Concat(...);

वैकल्पिक रूप से, .Union()डुप्लिकेट तत्वों को हटा देगा।


2
धन्यवाद; एकमात्र कारण जो मैंने पहले स्थान पर नहीं किया, वह यह है कि (मेरे लिए) ऐसा लगता है कि आपको अधिक संग्रह करने के लिए कुरूपता प्राप्त होगी। हालांकि इसमें मौजूदा LINQ फ़ंक्शन का उपयोग करने का लाभ है, जो भविष्य के डेवलपर्स की संभावना पहले से ही परिचित होंगे।
डोनट

2
.Union()टिप के लिए धन्यवाद । यह ध्यान में रखते हुए कि आपको अपने कस्टम प्रकार पर IComparer लागू करना होगा
गोंजो ३४५

29

मेरे लिए Concatएक विस्तार विधि के रूप में मेरे कोड में बहुत सुरुचिपूर्ण नहीं है जब मेरे पास कई बड़े अनुक्रम हैं। यह केवल एक कोडे इंडेंटेशन / स्वरूपण समस्या है और कुछ बहुत ही व्यक्तिगत है।

यकीन है कि यह इस तरह अच्छा लगता है:

var list = list1.Concat(list2).Concat(list3);

जब यह पढता है तो ऐसा नहीं है:

var list = list1.Select(x = > x)
   .Concat(list2.Where(x => true)
   .Concat(list3.OrderBy(x => x));

या जब ऐसा लगे:

return Normalize(list1, a, b)
    .Concat(Normalize(list2, b, c))
       .Concat(Normalize(list3, c, d));

या जो कुछ भी आपके पसंदीदा स्वरूपण है। अधिक जटिल कॉन्सर्ट के साथ चीजें खराब हो जाती हैं। उपरोक्त शैली के साथ मेरी तरह की संज्ञानात्मक असंगति का कारण यह है कि पहला अनुक्रम Concatविधि के बाहर झूठ बोलता है जबकि बाद के अनुक्रम अंदर झूठ बोलते हैं। मैं बल्कि स्टैटिक Concatविधि को सीधे कॉल करना पसंद करता हूं न कि विस्तार शैली को:

var list = Enumerable.Concat(list1.Select(x => x),
                             list2.Where(x => true));

अनुक्रमणिका के अधिक संख्या में समतुल्य विधि को मैं ओपी में ले जाता हूं:

public static IEnumerable<T> Concat<T>(params IEnumerable<T>[] sequences)
{
    return sequences.SelectMany(x => x);
}

इसलिए मैं लिख सकता हूं:

return EnumerableEx.Concat
(
    list1.Select(x = > x),
    list2.Where(x => true),
    list3.OrderBy(x => x)
);

बेहतर लग रहा है। अतिरिक्त, अन्यथा निरर्थक, कक्षा का नाम जो मुझे लिखना है वह मेरे लिए कोई समस्या नहीं है, यह देखते हुए कि मेरे अनुक्रम Concatकॉल के साथ क्लीनर दिखते हैं। यह C # 6 में एक समस्या से कम नहीं है । आप बस लिख सकते हैं:

return Concat(list1.Select(x = > x),
              list2.Where(x => true),
              list3.OrderBy(x => x));

कामना की सूची सी # में हमारे संचालकों के पास थी, कुछ इस प्रकार है:

list1 @ list2 // F#
list1 ++ list2 // Scala

उस तरह से बहुत क्लीनर।


4
मैं कोडिंग शैली के लिए आपकी चिंता की सराहना करता हूं। यह बहुत अधिक सुरुचिपूर्ण है।
ब्रायन रेनर

शायद आपके उत्तर का एक छोटा संस्करण यहां शीर्ष उत्तर के साथ विलय किया जा सकता है।
ब्रायन रेनर

2
मैं इस रूप में अच्छी तरह स्वरूपण की तरह - हालांकि मैं (जैसे अलग-अलग सूची कार्रवाई करने को प्राथमिकता देते Where, OrderBy) पहली स्पष्टता के लिए, खासकर अगर वे कुछ भी इस उदाहरण से कहीं अधिक जटिल।
ब्रिचिन्स

27

मामले के लिए जब आपके पास संग्रह का एक संग्रह है, अर्थात List<List<T>>, Enumerable.Aggregateसभी सूचियों को एक में संयोजित करने का एक और अधिक सुंदर तरीका है:

var combined = lists.Aggregate((acc, list) => { return acc.Concat(list); });

1
आप listsयहां पहले कैसे पहुंचे? ओपी में यह पहली समस्या है। अगर उसके पास collection<collection>शुरू करने के लिए एक SelectManyरास्ता है तो बस सरल है।
नवफाल

यकीन नहीं हुआ कि क्या हुआ, लेकिन यह गलत सवाल का जवाब देता प्रतीत होता है। इसे प्रतिबिंबित करने के लिए संपादित उत्तर। बहुत से लोग यहाँ समाप्त होने लगते हैं क्योंकि एक सूची <सूची <T >>
astreltsov



7

आप हमेशा एग्रीगेट का इस्तेमाल कॉनैट के साथ कर सकते हैं ...

        var listOfLists = new List<List<int>>
        {
            new List<int> {1, 2, 3, 4},
            new List<int> {5, 6, 7, 8},
            new List<int> {9, 10}
        };

        IEnumerable<int> combined = new List<int>();
        combined = listOfLists.Aggregate(combined, (current, list) => current.Concat(list)).ToList();

1
अब तक का सबसे अच्छा समाधान।
ओलेग

@Oleg SelectManyबस सरल है।
नवफ़ल

6

एकमात्र तरीका जो मैं देख रहा हूं वह उपयोग करना है Concat()

 var foo = new List<int> { 1, 2, 3 };
 var bar = new List<int> { 4, 5, 6 };
 var tor = new List<int> { 7, 8, 9 };

 var result = foo.Concat(bar).Concat(tor);

लेकिन आपको तय करना चाहिए कि क्या बेहतर है:

var result = Combine(foo, bar, tor);

या

var result = foo.Concat(bar).Concat(tor);

एक बिंदु क्यों Concat()बेहतर विकल्प होगा कि यह किसी अन्य डेवलपर के लिए अधिक स्पष्ट होगा। अधिक पठनीय और सरल।


3

आप संघ का उपयोग इस प्रकार कर सकते हैं:

var combined=foo.Union(bar).Union(baz)...

यह समान तत्वों को हटा देगा, हालांकि, यदि आपके पास वे हैं, तो आप Concatइसके बजाय उपयोग करना चाह सकते हैं ।


4
नहीं! Enumerable.Unionएक सेट संघ है जो वांछित परिणाम नहीं देता है (यह केवल एक बार डुप्लिकेट उपज देता है)।
जसन

हाँ, मुझे वस्तुओं के विशिष्ट उदाहरणों की आवश्यकता है, क्योंकि मुझे उन पर कुछ विशेष प्रसंस्करण करने की आवश्यकता है। intमेरे उदाहरण में उपयोग करने से लोगों को थोड़ा बहुत धक्का लग सकता है; लेकिन Unionइस मामले में मेरे लिए काम नहीं करेगा।
डोनट

2

संग्रह शुरुआती का उपयोग कर एक युगल तकनीक -

इन सूचियों को मानते हुए:

var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 4, 5, 6 };

SelectMany एक सरणी आरंभीकरण के साथ (वास्तव में मेरे लिए यह सुंदर नहीं है, लेकिन किसी भी सहायक कार्य पर भरोसा नहीं करता है):

var combined = new []{ list1, list2 }.SelectMany(x => x);

जोड़ें में एक सूची विस्तार को परिभाषित करें जो शुरुआती IEnumerable<T>में अनुमति देता List<T> है :

public static class CollectionExtensions
{
    public static void Add<T>(this ICollection<T> collection, IEnumerable<T> items)
    {
        foreach (var item in items) collection.Add(item);
    }
}

फिर आप एक नई सूची बना सकते हैं जिसमें दूसरों के तत्व शामिल हैं (यह एकल आइटम को मिश्रित करने की अनुमति भी देता है)।

var combined = new List<int> { list1, list2, 7, 8 };

1

यह देखते हुए कि आप अलग-अलग संग्रहों के समूह के साथ शुरू कर रहे हैं, मुझे लगता है कि आपका समाधान बल्कि सुरुचिपूर्ण है। आप उन्हें एक साथ सिलाई करने के लिए कुछ करने जा रहे हैं।

अपने कंबाइन विधि से विस्तार विधि बनाने के लिए यह अधिक सुविधाजनक रूप से सुविधाजनक होगा, जो आपको कहीं भी जाने के लिए उपलब्ध कराएगा।


मुझे एक्सटेंशन मेथड आईडिया पसंद है, मैं सिर्फ व्हील को फिर से मजबूत नहीं करना चाहता था अगर LINQ में पहले से ही एक ऐसा तरीका होता जो एक ही काम करता (और तुरंत लाइन के नीचे अन्य डेवलपर्स के लिए समझ में आता)
डोनट

1

इसके लिए आपको बस जरूरत है IEnumerable<IEnumerable<T>> lists:

var combined = lists.Aggregate((l1, l2) => l1.Concat(l2));

यह सभी वस्तुओं listsको एक में IEnumerable<T>(डुप्लिकेट के साथ) संयोजित करेगा । डुप्लिकेट को हटाने के Unionबजाय उपयोग करें Concat, जैसा कि अन्य उत्तरों में उल्लेख किया गया है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.