Unir dos listas juntas


333

Si tengo dos listas de tipo cadena (o cualquier otro tipo), ¿cuál es una forma rápida de unir las dos listas?

El orden debe permanecer igual. Deben eliminarse los duplicados (aunque cada elemento en ambos enlaces es único). No encontré mucho en esto cuando busqué en Google y no quería implementar ninguna interfaz .NET para la velocidad de entrega.


55
¿Importa el orden? ¿Quieres retener duplicados?
Larsenal

Respuestas:


574

Tu podrías intentar:

List<string> a = new List<string>();
List<string> b = new List<string>();

a.AddRange(b);

Página de MSDN para AddRange

Esto conserva el orden de las listas, pero no elimina los duplicados que Unionharían.

Esto cambia la lista a. Si desea conservar las listas originales, debe usar Concat(como se señala en las otras respuestas):

var newList = a.Concat(b);

Esto devuelve un valor IEnumerablesiempre que ano sea nulo.


27
Nadie realmente ha entrado cuándo usar qué método. AddRange edita una lista en su lugar, agregando la segunda lista (como si llamaras .Add (foo) varias veces). Los métodos de extensión Concat y Union no cambian la lista original. Construyen perezosamente un nuevo IEnumerable y ni siquiera accederán a los miembros de la lista original a menos que sea necesario. Como se señaló, Union elimina los duplicados mientras que los otros no.
ShawnFumo

44
¿Alguien sabe cuál es la complejidad de este método? (Es una pena que Microsoft no proporcione esta información importante como parte de su MSDN)
Jacob

2
Le recomiendo que compruebe esta buena comparación de los diversos enfoques. También muestre algunos análisis de rendimiento de varias opciones: Colecciones de combinación
BogeyMan

Esto funciona a la perfección. Estaba usando concat () en más de medio millón de elementos, lo que tomó varios minutos. Este enfoque lleva menos de 5 segundos.
GreenFerret95

111

La forma con la menor sobrecarga de espacio es usar el método de extensión Concat.

var combined = list1.Concat(list2);

Crea una instancia de la IEnumerable<T>cual enumerará los elementos de list1 y list2 en ese orden.


2
recuerde using System.Linq;poder usar Concat
tothemario

43

El método de la Unión podría abordar sus necesidades. No especificó si el pedido o los duplicados eran importantes.

Tome dos IEnumerables y realice una unión como se ve aquí:

int[] ints1 = { 5, 3, 9, 7, 5, 9, 3, 7 };
int[] ints2 = { 8, 3, 6, 4, 4, 9, 1, 0 };

IEnumerable<int> union = ints1.Union(ints2);

// yields { 5, 3, 9, 7, 8, 6, 4, 1, 0 } 

24

Algo como esto:

firstList.AddRange (secondList);

O bien, puede usar el método de extensión 'Unión' que se define en System.Linq. Con 'Unión', también puede especificar un comparador, que puede usarse para especificar si un artículo debe estar unido o no.

Me gusta esto:

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

var result = one.Union (second, new EqComparer ());

foreach( int x in result )
{
    Console.WriteLine (x);
}
Console.ReadLine ();

#region IEqualityComparer<int> Members
public class EqComparer : IEqualityComparer<int>
{
    public bool Equals( int x, int y )
    {
        return x == y;
    }

    public int GetHashCode( int obj )
    {
        return obj.GetHashCode ();
    }
}
#endregion

17
targetList = list1.Concat(list2).ToList();

Está funcionando bien, creo que sí. Como se dijo anteriormente, Concat devuelve una nueva secuencia y, al convertir el resultado en Lista, hace el trabajo perfectamente. Las conversiones implícitas pueden fallar a veces cuando se usa el método AddRange.


13

Si existen algunos elementos en ambas listas, puede usar

var all = list1.Concat(list2).Concat(list3) ... Concat(listN).Distinct().ToList();

7

Siempre que sean del mismo tipo, es muy simple con AddRange:

list2.AddRange(list1);

7
var bigList = new List<int> { 1, 2, 3 }
    .Concat(new List<int> { 4, 5, 6 })
    .ToList(); /// yields { 1, 2, 3, 4, 5, 6 }

Me gusta esto también. Muy simple. Gracias.
GurdeepS

Me gusta esto porque no muta ninguna de las listas.
Ev.


4
List<string> list1 = new List<string>();
list1.Add("dot");
list1.Add("net");

List<string> list2 = new List<string>();
list2.Add("pearls");
list2.Add("!");

var result = list1.Concat(list2);


2

Una forma, no he visto mencionar que puede ser un poco más robusto, especialmente si desea alterar cada elemento de alguna manera (por ejemplo, quería .Trim()todos los elementos.

List<string> a = new List<string>();
List<string> b = new List<string>();
// ...
b.ForEach(x=>a.Add(x.Trim()));

1

Ver este enlace

public class ProductA
{ 
public string Name { get; set; }
public int Code { get; set; }
}

public class ProductComparer : IEqualityComparer<ProductA>
{

public bool Equals(ProductA x, ProductA y)
{
    //Check whether the objects are the same object. 
    if (Object.ReferenceEquals(x, y)) return true;

    //Check whether the products' properties are equal. 
    return x != null && y != null && x.Code.Equals(y.Code) && x.Name.Equals(y.Name);
    }

public int GetHashCode(ProductA obj)
{
    //Get hash code for the Name field if it is not null. 
    int hashProductName = obj.Name == null ? 0 : obj.Name.GetHashCode();

    //Get hash code for the Code field. 
    int hashProductCode = obj.Code.GetHashCode();

    //Calculate the hash code for the product. 
    return hashProductName ^ hashProductCode;
}
}


    ProductA[] store1 = { new ProductA { Name = "apple", Code = 9 }, 
                   new ProductA { Name = "orange", Code = 4 } };

    ProductA[] store2 = { new ProductA { Name = "apple", Code = 9 }, 
                   new ProductA { Name = "lemon", Code = 12 } };

// Obtenga los productos de ambas matrices // excluyendo duplicados.

IEnumerable<ProductA> union =
  store1.Union(store2);

foreach (var product in union)
    Console.WriteLine(product.Name + " " + product.Code);

/*
    This code produces the following output:

    apple 9
    orange 4
    lemon 12
*/

1

Las dos opciones que uso son:

list1.AddRange(list2);

o

list1.Concat(list2);

Sin embargo, noté que cuando usaba el AddRangemétodo con una función recursiva, que se llama a sí mismo muy a menudo, recibí una excepción SystemOutOfMemoryException porque se alcanzó el número máximo de dimensiones.

(Mensaje traducido por Google)
Las dimensiones de la matriz excedieron el rango admitido.

Usando Concatresuelto ese problema.


0

Solo quería probar cómo Union funciona con el comparador predeterminado en colecciones superpuestas de objetos de tipo de referencia.

Mi objeto es:

class MyInt
{
    public int val;

    public override string ToString()
    {
        return val.ToString();
    }
}

Mi código de prueba es:

MyInt[] myInts1 = new MyInt[10];
MyInt[] myInts2 = new MyInt[10];
int overlapFrom = 4;
Console.WriteLine("overlapFrom: {0}", overlapFrom);

Action<IEnumerable<MyInt>, string> printMyInts = (myInts, myIntsName) => Console.WriteLine("{2} ({0}): {1}", myInts.Count(), string.Join(" ", myInts), myIntsName);

for (int i = 0; i < myInts1.Length; i++)
    myInts1[i] = new MyInt { val = i };
printMyInts(myInts1, nameof(myInts1));

int j = 0;
for (; j + overlapFrom < myInts1.Length; j++)
    myInts2[j] = myInts1[j + overlapFrom];
for (; j < myInts2.Length; j++)
    myInts2[j] = new MyInt { val = j + overlapFrom };
printMyInts(myInts2, nameof(myInts2));

IEnumerable<MyInt> myUnion = myInts1.Union(myInts2);
printMyInts(myUnion, nameof(myUnion));

for (int i = 0; i < myInts2.Length; i++)
    myInts2[i].val += 10;
printMyInts(myInts2, nameof(myInts2));
printMyInts(myUnion, nameof(myUnion));

for (int i = 0; i < myInts1.Length; i++)
    myInts1[i].val = i;
printMyInts(myInts1, nameof(myInts1));
printMyInts(myUnion, nameof(myUnion));

El resultado es:

overlapFrom: 4
myInts1 (10): 0 1 2 3 4 5 6 7 8 9
myInts2 (10): 4 5 6 7 8 9 10 11 12 13
myUnion (14): 0 1 2 3 4 5 6 7 8 9 10 11 12 13
myInts2 (10): 14 15 16 17 18 19 20 21 22 23
myUnion (14): 0 1 2 3 14 15 16 17 18 19 20 21 22 23
myInts1 (10): 0 1 2 3 4 5 6 7 8 9
myUnion (14): 0 1 2 3 4 5 6 7 8 9 20 21 22 23

Entonces, todo funciona bien.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.