Aggiungi due elenchi di lunghezza diversa in c #

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

a + b dovrebbe darmi 2,4,6,4,5

obvisouly posso scrivere un ciclo ma c’è un modo migliore? usando linq?

È ansible utilizzare un’operazione “zip” modificata abbastanza facilmente, ma non integrata. Qualcosa come:

  static void Main() { var a = new List { 1, 2, 3 }; var b = new List { 1, 2, 3, 4, 5 }; foreach (var c in a.Merge(b, (x, y) => x + y)) { Console.WriteLine(c); } } static IEnumerable Merge(this IEnumerable first, IEnumerable second, Func 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; } } } 

Utilizzando l’operatore Zip di .NET 4.0:

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

Se vuoi generalizzare questo, controlla quale ha più elementi e usalo come “b” sopra.

 Enumerable.Range(0, new[] { a.Count, b.Count }.Max()) .Select(n => a.ElementAtOrDefault(n) + b.ElementAtOrDefault(n)); 

Ho dovuto modificare leggermente la soluzione di Marc per il mio utilizzo per consentire elenchi di tipi diversi, quindi ho pensato di postare in caso che qualcun altro ne avesse bisogno.

 public static IEnumerable Merge(this IEnumerable first, IEnumerable second, Func 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); } } } } 

Cosa ne pensi di questo:

 List 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(); 

Di seguito è una soluzione al tuo problema.

 List a = new List{1,2,3}; List b = new List{1,2,3,4,5}; List sum = new List(); 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]); 

La brutta soluzione 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]); 

In questo caso, se gli elenchi sono della stessa lunghezza o di lunghezze diverse, non importa. La libreria di classi .NET non ha il metodo Enumerable.Zip per combinare due sequenze (verrà solo in .NET 4.0) e in questo caso avresti bisogno di qualcosa del genere. Quindi devi scrivere un ciclo, o scrivere il tuo Zip (che implicherebbe comunque un loop).

Ci sono alcuni hack per spremere tutto questo in una singola query LINQ senza loop, coinvolgendo join su indici, ma quelli sarebbero molto lenti e davvero inutili.

Cosa è successo 1 e agli extra 2 e 3 ? Se stai cercando valori distinti:

 var one = new List { 1, 2, 3 }; var two = new List { 1, 2, 3, 4, 5 }; foreach (var x in one.Union(two)) Console.Write("{0} ", x); 

Ti darò 1 2 3 4 5

Se stai cercando solo la seconda lista aggiunta alla prima, allora:

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

ti darò 1 2 3 1 2 3 4 5

Edit : Oh, vedo, stai cercando una sorta di Zip , ma che restituisce le parti extra. Prova questo:

 public static IEnumerable Zip( this IEnumerable one, IEnumerable two, Func 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); } } } } 

ed ecco uno che è più simile a una normale funzione di zip, che non restituisce gli extra:

 public static IEnumerable Zip( this IEnumerable one, IEnumerable two, Func 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)); } } } } 

Esempio di utilizzo:

 var one = new List { 1, 2, 3, 4, 5}; var two = new List { 'h', 'e', 'l', 'l', 'o' }; foreach (var x in one.Zip(two, (a,b) => new {A = a, B =b })) Console.WriteLine("{0} => '{1}'", xA, xB); 

Risultati in:

1 => ‘h’
2 => ‘e’
3 => ‘l’
4 => ‘l’
5 => ‘o’

Eccone altri 3:

Rendi le liste delle stesse dimensioni, quindi seleziona semplicemente.

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

Non rendili della stessa dimensione, ma passa per il più lungo e controlla la fine del raggio più corto (salva shortList.Count per un guadagno perfetto):

 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 mentre puoi, poi Skip e Union il resto:

 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)); 

Come combinazione delle risposte di Marc e Damian , puoi semplicemente usare questo codice, che è un po ‘più pronto per la produzione:

 public static class EnumerableExtensions { public static IEnumerable Merge(this IEnumerable first, IEnumerable second, Func operation) { return Merge(first, second, operation); } public static IEnumerable Merge(this IEnumerable first, IEnumerable second, Func operation) { return Merge(first, second, operation); } public static IEnumerable Merge(this IEnumerable first, IEnumerable second, Func operation) { if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); using (var iter1 = first.GetEnumerator()) using (var iter2 = second.GetEnumerator()) { while (iter1.MoveNext()) { yield return iter2.MoveNext() ? operation(iter1.Current, iter2.Current) : operation(iter1.Current, default); } while (iter2.MoveNext()) { yield return operation(default, iter2.Current); } } } } 

La mia implementazione utilizzando un loop:

 List shorter, longer; if (a.Count > b.Count) { shorter = b; longer = a } else { shorter = a; longer = b; } List result = new List(longer); for (int i = 0; i < shorter.Count; ++i) { result[i] += shorter[i]; }