List<double> a = new List<double>{1,2,3};
List<double> b = new List<double>{1,2,3,4,5};
a + b me debe dar 2,4,6,4,5Añadir dos listas de diferente longitud en C#
obvisouly puedo escribir un bucle, pero hay una manera mejor? usando linq?
List<double> a = new List<double>{1,2,3};
List<double> b = new List<double>{1,2,3,4,5};
a + b me debe dar 2,4,6,4,5Añadir dos listas de diferente longitud en C#
obvisouly puedo escribir un bucle, pero hay una manera mejor? usando linq?
se puede utilizar una operación de "zip" modificado con bastante facilidad, pero nada construido en algo como:.
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;
}
}
}
A continuación se muestra una solución a su problema.
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]);
Desde OP: "Obvisouly puedo escribir un bucle, pero ¿hay una mejor manera?" –
Touche again ..... – jjnguy
El código es bueno, sin embargo; Hice +1 para anular el voto a favor (injusto, IMO). –
En este caso, si las listas son de la misma longitud o de longitudes diferentes, que en realidad no importa. biblioteca de clases .NET no tiene Enumerable.Zip
método para combinar dos secuencias (sólo vendrá en .NET 4.0), y que necesitaría algo así aquí de cualquier manera. Así que o bien tiene que escribir un bucle, o para escribir su propia Zip
(que todavía implicaría un bucle).
Hay algunos trucos para exprimir todo esto en una sola consulta LINQ sin bucles, con la participación de unirse en los índices, pero esos serían muy lento y realmente inútil.
¿Por qué, exactamente, obtuve un -1? Si es incorrecto en los hechos, señale los problemas específicos. De lo contrario, no veo cómo esta no es una respuesta directa a la pregunta tal como se establece ("puedo escribir un ciclo, pero ¿hay una mejor manera? ¿Usar linq?"). –
Mi solución utilizó LINQ sin bucle. Obviamente, habrá LINQ hecho por LINQ, pero será escrito por el compilador. –
¿Qué pasó con el 1
y el extra 2
y 3
? Si usted está buscando los valores distintos:
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);
le dará 1 2 3 4 5
Si usted está buscando sólo la segunda lista anexa a la primera a continuación:
foreach(var x in one.Concat(two)) // ...
le dará 1 2 3 1 2 3 4 5
Editar: Oh, ya veo, estás buscando un tipo de Zip
, pero que devuelve las piezas adicionales.Prueba esto:
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);
}
}
}
}
y aquí hay uno que es más como una función postal normal, que no devuelve los extras: Uso
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));
}
}
}
}
Ejemplo:
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);
Resultados en :
1 => 'h'
2 => 'e'
3 => 'l'
4 => 'l'
5 => 'o'
En realidad está tratando de hacer una suma por pares de elementos en ambas listas, tratando elementos faltantes de listas más cortas como 0. –
¡Ya veo! He editado mi respuesta para incluir esa funcionalidad. – IRBMe
Esto es incorrecto; el valor de Current no está definido, no se sabe que MoveNext devuelve true; de hecho, para los iteradores más antiguos lanzarán una excepción si haces esto; vea http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.current.aspx: "Current también arroja una excepción si la última llamada a MoveNext devolvió false, que indica el final de la colección. " –
Mi aplicación usando un bucle:
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];
}
Tenga en cuenta que esto es una adición a mi otra respuesta que explica por qué esto no se puede hacer a través de LINQ en 3.5. Es solo un intento de proporcionar la implementación más corta y más legible basada en bucle. –
El feo solución 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]);
Enumerable.Range(0, new[] { a.Count, b.Count }.Max())
.Select(n => a.ElementAtOrDefault(n) + b.ElementAtOrDefault(n));
Personalmente, usaría 'Math.Max (a.Count, b.Count)' en lugar de 'new [] {a.Count, b.Count} .Max()'. –
buen punto, más corto que el mío. – gabe
ElementAtOrDefault, siendo IEnumerable, (probablemente) atravesará toda la lista. ¿Probablemente es mejor hacer el 'a.Count> n más largo? a [n]: 0' en su lugar. –
El uso de .NET 4.0 Zip operador:
var sums = b.Zip(a, (x, y) => x + y)
.Concat(b.Skip(a.Count()));
Si desea generalizar esto, compruebe que tiene más elementos y usar eso como la "b" anterior.
"compruebe que tiene más elementos y utilícelo como la" b "de arriba." - ¿Cómo? –
@firsttimer (a.Count> b.Count)? a.Skip (b.Count): b.Skip (a.Count) – stannius
¿Qué tal esto:
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();
¿Qué sucede si mis colecciones a/b son IEnumerable y no son Lists? –
En ese caso, para ser eficiente, deberá iterar ambas listas simultáneamente, así que use la implementación de Marc Gravell. – Handcraftsman
Aquí hay 3 más:
Hacer las listas del mismo tamaño, a continuación, sólo sencilla Seleccionar.
(a.Count < b.Count ? a : b).AddRange(new double[Math.Abs(a.Count - b.Count)]);
var c = a.Select((n, i) => n + b[i]);
no les haga el mismo tamaño, pero pasan por el más largo y compruebe si el final del rango en el más corto (shortList.Count tienda para la ganancia fácil perf):
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
mientras se puede, a continuación, Skip
y Union
el 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));
tuve que ajustar ligeramente solución de Marc para mi uso para permitir listas de diferentes ty pes, así que pensé en publicar en caso de que alguien más lo necesite.
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);
}
}
}
}
Estaba a punto de publicar una solución para el mismo problema que estaba abordando. Sorprendido de que no haya recibido más votaciones ascendentes porque, en mi opinión, es mejor (ya que es más flexible y algo que cabría esperar en una utilidad linq). – hbulens
Tendrá que escribir un bucle. – jjnguy
¿Está buscando valores distintos (sin repeticiones? Además, ¿qué pasa con el 1? –
¿Quiere decir {2,4,6,4,5}? Es decir, {1 + 1, 2 + 2, 3 + 3, 0+ 4, 0 + 5)? –