2009-07-27 11 views
16
List<double> a = new List<double>{1,2,3}; 
List<double> b = new List<double>{1,2,3,4,5}; 

ए + बी मुझे 2,4,6,4,5सी # में विभिन्न अवधि की दो सूचियां जोड़ें

obvisouly मैं एक पाश लिखने लेकिन वहाँ एक बेहतर तरीका है सकते हैं देना चाहिए? linq का उपयोग कर?

+0

आपको एक लूप लिखना होगा। – jjnguy

+0

क्या आप अलग-अलग मूल्यों की तलाश कर रहे हैं (कोई पुनरावृत्ति नहीं? इसके अलावा, 1? –

+1

के बारे में क्या मतलब है {2,4,6,4,5}? Ie {1 + 1, 2 + 2, 3 + 3, 0+ 4, 0 + 5)? –

उत्तर

22

आप आसानी से पर्याप्त एक संशोधित "ज़िप" आपरेशन इस्तेमाल कर सकते हैं, लेकिन कुछ नहीं में बनाया तरह:।

static void Main() { 
     var a = new List<int> { 1, 2, 3 }; 
     var b = new List<int> { 1, 2, 3, 4, 5 }; 
     foreach (var c in a.Merge(b, (x, y) => x + y)) { 
      Console.WriteLine(c); 
     } 
    } 
    static IEnumerable<T> Merge<T>(this IEnumerable<T> first, 
      IEnumerable<T> second, Func<T, T, T> operation) { 
     using (var iter1 = first.GetEnumerator()) 
     using (var iter2 = second.GetEnumerator()) { 
      while (iter1.MoveNext()) { 
       if (iter2.MoveNext()) { 
        yield return operation(iter1.Current, iter2.Current); 
       } else { 
        yield return iter1.Current; 
       } 
      } 
      while (iter2.MoveNext()) { 
       yield return iter2.Current; 
      } 
     } 
    } 
+0

होना चाहिए आपका समाधान इतना लंबा क्यों है? – jjnguy

+3

क्योंकि यह किसी भी अनुक्रम और संचालन के साथ पुन: प्रयोज्य है - न केवल सूचियों/अनुक्रमणिका/अतिरिक्त। ऊर्ध्वाधर अंतरिक्ष फिक्स्ड ... बेहतर? –

+1

छूना! – jjnguy

1

नीचे अपनी समस्या का समाधान है।

List<double> a = new List<double>{1,2,3}; 
List<double> b = new List<double>{1,2,3,4,5}; 

List<double> sum = new List<double>(); 
int max = Math.Min(a.Count, b.Count); 
for (int i = 0; i < max; i++){ 
    sum.Add(a[i] + b[i]); 
} 

if (a.Count < b.Count) 
    for (int i = max i < b.Count) 
     sum.Add(b[i]); 
else 
    for (int i = max i < a.Count) 
    sum.Add(a[i]); 
+0

ओपी से: "obvisouly मैं एक लूप लिख सकता हूं लेकिन क्या एक बेहतर तरीका है?" –

+1

फिर से टच ... – jjnguy

+0

कोड अच्छा है, यद्यपि; मैंने (अनुचित, आईएमओ) डाउनवोट को अस्वीकार करने के लिए +1 किया है। –

0

इस मामले में, क्या सूचियां समान लंबाई या विभिन्न लंबाई के हैं, यह वास्तव में कोई फर्क नहीं पड़ता। .NET क्लास लाइब्रेरी में 0 अनुक्रमों को गठबंधन करने के लिए Enumerable.Zip विधि नहीं है (यह केवल .NET 4.0 में आ जाएगा), और आपको किसी भी तरह से इस तरह की आवश्यकता होगी। तो आपको या तो एक लूप लिखना होगा, या अपना खुद का Zip लिखना होगा (जिसमें अभी भी एक लूप शामिल होगा)।

कुछ हैक्स को बिना किसी लूप के एक LINQ क्वेरी में निचोड़ने के लिए, इंडेक्स पर शामिल होने सहित, लेकिन वे बहुत धीमे और वास्तव में व्यर्थ होंगे।

+0

क्यों, बिल्कुल, क्या यह -1 प्राप्त हुआ? यदि यह वास्तव में गलत है, तो कृपया विशिष्ट समस्याओं को इंगित करें। अन्यथा, मैं नहीं देखता कि यह सवाल का सीधा जवाब नहीं है जैसा कि कहा गया है ("मैं एक लूप लिख सकता हूं लेकिन क्या एक बेहतर तरीका है? Linq का उपयोग कर?")। –

+0

मेरा समाधान LINQ के साथ कोई लूप नहीं था। स्पष्ट रूप से LINQ द्वारा किया गया लूप होगा, लेकिन यह संकलक द्वारा लिखा जाएगा। –

0

1 और अतिरिक्त 2 और 3 पर क्या हुआ? आप अलग-अलग मान लिए देख रहे हैं:

var one = new List<int> { 1, 2, 3 }; 
var two = new List<int> { 1, 2, 3, 4, 5 }; 

foreach (var x in one.Union(two)) Console.Write("{0} ", x); 

आप 1 2 3 4 5

देंगे तुम सिर्फ दूसरा तो पहले से संलग्न सूची के लिए देख रहे हैं:

foreach(var x in one.Concat(two)) // ... 

आप दे देंगे 1 2 3 1 2 3 4 5

संपादित: ओह, मैं देख रहा हूँ, आपके एक प्रकार के लिए देख रहे हैं, लेकिन जो अतिरिक्त भागों को लौटाता है।इस प्रयास करें:

public static IEnumerable<V> Zip<T, U, V>(
    this IEnumerable<T> one, 
    IEnumerable<U> two, 
    Func<T, U, V> f) 
{ 
    using (var oneIter = one.GetEnumerator()) { 
     using (var twoIter = two.GetEnumerator()) { 
      while (oneIter.MoveNext()) { 
       twoIter.MoveNext(); 
       yield return f(oneIter.Current, 
        twoIter.MoveNext() ? 
         twoIter.Current : 
         default(U)); 
      } 

      while (twoIter.MoveNext()) { 
       yield return f(oneIter.Current, twoIter.Current); 
      } 
     } 
    } 
} 

और यहाँ एक और एक सामान्य जिप समारोह की तरह है कि, जो अतिरिक्त वापस नहीं करता है:

public static IEnumerable<V> Zip<T, U, V>(
    this IEnumerable<T> one, 
    IEnumerable<U> two, 
    Func<T, U, V> f) 
{ 
    using (var oneIter = one.GetEnumerator()) { 
     using (var twoIter = two.GetEnumerator()) { 
      while (oneIter.MoveNext()) { 
       yield return f(oneIter.Current, 
        twoIter.MoveNext() ? 
         twoIter.Current : 
         default(U)); 
      } 
     } 
    } 
} 

उदाहरण उपयोग:

var one = new List<int> { 1, 2, 3, 4, 5}; 
var two = new List<char> { 'h', 'e', 'l', 'l', 'o' }; 

foreach (var x in one.Zip(two, (a,b) => new {A = a, B =b })) 
    Console.WriteLine("{0} => '{1}'", x.A, x.B); 

में परिणाम :

1 => 'एच'
2 => 'ई'
3 => 'l'
4 => 'l'
5 => 'o'

+0

वह वास्तव में दोनों सूचियों में तत्वों की एक जोड़ी राशि करने की कोशिश कर रहा है, छोटे सूचियों से लापता तत्वों का इलाज 0. –

+0

जैसा मैं देखता हूं! मैंने उस कार्यक्षमता को शामिल करने के लिए अपना उत्तर संपादित कर लिया है। – IRBMe

+0

यह गलत है; वर्तमान का मूल्य अपरिभाषित है, आपको यह नहीं पता कि MoveNext सत्य लौटाता है; वास्तव में, पुराने इटरेटर के लिए यदि आप ऐसा करते हैं तो वे अपवाद फेंक देंगे; http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.current.aspx देखें: "वर्तमान में एक अपवाद फेंकता है यदि MoveNext के अंतिम कॉल को झूठा लौटा दिया गया है, जो संग्रह के अंत को इंगित करता है। " –

-2

एक पाश का उपयोग कर मेरे कार्यान्वयन:

List<double> shorter, longer; 
if (a.Count > b.Count) 
{ 
    shorter = b; longer = a 
} 
else 
{ 
    shorter = a; longer = b; 
} 

List<double> result = new List<double>(longer); 
for (int i = 0; i < shorter.Count; ++i) 
{ 
    result[i] += shorter[i]; 
} 
+0

ध्यान दें कि यह मेरे दूसरे उत्तर के लिए एक अतिरिक्त है जो बताता है कि यह LINQ के माध्यम से 3.5 में क्यों नहीं किया जा सकता है। यह केवल सबसे छोटा और सबसे पठनीय लूप-आधारित कार्यान्वयन प्रदान करने का प्रयास है। –

1

बदसूरत LINQ समाधान:

var sum = Enumerable.Range(0, (a.Count > b.Count) ? a.Count : b.Count) 
    .Select(i => (a.Count > i && b.Count > i) ? a[i] + b[i] : (a.Count > i) ? a[i] : b[i]); 
6
Enumerable.Range(0, new[] { a.Count, b.Count }.Max()) 
    .Select(n => a.ElementAtOrDefault(n) + b.ElementAtOrDefault(n));
+1

व्यक्तिगत रूप से, मैं 'नए [] {ए। काउंटर, बी। काउंटर} के बजाय' Math.Max ​​(ए। गणना, बी। गणना) 'का उपयोग करूंगा .मैक्स()'। –

+0

अच्छा बिंदु, मेरा से छोटा। – gabe

+3

ElementAtOrDefault, IENumerable के लिए होने के नाते, (संभवतः) पूरी सूची को पार करेगा। शायद 'ए। काउंटर> एन करने के लिए शायद बेहतर है? एक [एन]: 0' इसके बजाए। –

12

.NET 4.0 के Zip ऑपरेटर का उपयोग करना:

var sums = b.Zip(a, (x, y) => x + y) 
      .Concat(b.Skip(a.Count())); 

यदि आप इसे सामान्य बनाना चाहते हैं, तो जांच करें कि किस तत्व में अधिक तत्व हैं और इसका उपयोग "बी" के रूप में करें।

+0

"जांचें जिसमें अधिक तत्व हैं और उपरोक्त" बी "के रूप में इसका उपयोग करें।" - किस तरह? –

+1

@ फर्स्टटाइमर (ए। काउंटर> बी। काउंटर)? ए। स्किप (बी। काउंटर): बी। स्किप (ए। काउंटर) – stannius

2

कैसे इस बारे में:

List<double> doubles = Enumerable.Range(0, Math.Max(a.Count, b.Count)) 
    .Select(x => (a.Count > x ? a[x] : 0) + (b.Count > x ? b[x] : 0)) 
    .ToList(); 
+0

क्या होगा यदि मेरे ए/बी संग्रह आईनेमरेबल हैं और सूची नहीं हैं? –

+0

उस मामले में कुशल होने के लिए आपको एक साथ दोनों सूचियों को फिर से शुरू करना होगा ताकि मार्क ग्रेवेल के कार्यान्वयन का उपयोग किया जा सके। – Handcraftsman

0

यहां 3 और भी है:

सूचियों एक ही आकार है, तो बस साधारण का चयन करें।

(a.Count < b.Count ? a : b).AddRange(new double[Math.Abs(a.Count - b.Count)]); 
var c = a.Select((n, i) => n + b[i]); 

उन्हें एक ही आकार मत करना, लेकिन सबसे लंबे समय तक के माध्यम से जाने के लिए और कम से कम (आसान पर्फ़ लाभ के लिए दुकान shortList.Count) पर सीमा की समाप्ति के लिए जाँच:

var longList = a.Count > b.Count ? a : b; 
var shortList = longList == a ? b : a; 
var c = longList.Select((n, i) => n + (shortList.Count > i ? shortList[i] : 0)); 

Take जबकि आप कर सकते हैं, तो Skip और Union बाकी:

var c = a.Take(Math.Min(a.Count, b.Count)) 
     .Select((n, i) => n + b[i]) 
     .Union(a.Skip(Math.Min(a.Count, b.Count)); 
5

मैं थोड़ा अलग Ty की सूची के लिए अनुमति देने के लिए अपने प्रयोग के लिए मार्क के समाधान को समायोजित करने के लिए किया था पेस, तो मैंने सोचा कि मैं किसी और को परेशान करने में पोस्ट करूंगा।

public static IEnumerable<TResult> Merge<TFirst,TSecond,TResult>(this IEnumerable<TFirst> first, 
      IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> operation) { 
    using (var iter1 = first.GetEnumerator()) { 
     using (var iter2 = second.GetEnumerator()) { 
      while (iter1.MoveNext()) { 
       if (iter2.MoveNext()) { 
        yield return operation(iter1.Current, iter2.Current); 
       } else { 
        yield return operation(iter1.Current, default(TSecond)); 
       } 
      } 
      while (iter2.MoveNext()) { 
       yield return operation(default(TFirst), iter2.Current); 
      } 
     } 
    } 
} 
+0

मैं उसी समस्या का समाधान पोस्ट करने वाला था जिसे आप संबोधित कर रहे थे। आश्चर्यचकित यह अधिक अपवर्तित नहीं हुआ है क्योंकि मेरी राय में यह बेहतर है (क्योंकि यह अधिक लचीला है और आप एक लिनक्स उपयोगिता में कुछ उम्मीद करेंगे)। – hbulens

संबंधित मुद्दे