Unire due liste insieme


333

Se ho due elenchi di tipo stringa (o qualsiasi altro tipo), qual è un modo rapido per unire i due elenchi?

L'ordine dovrebbe rimanere lo stesso. I duplicati devono essere rimossi (sebbene ogni elemento in entrambi i collegamenti sia univoco). Non ho trovato molto su questo quando cercavo su Google e non volevo implementare alcuna interfaccia .NET per la velocità di consegna.


5
L'ordine è importante? Vuoi conservare i duplicati?
Larsenal,

Risposte:


574

Puoi provare:

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

a.AddRange(b);

Pagina MSDN per AddRange

Ciò preserva l'ordine delle liste, ma non rimuove i duplicati che Unionfarebbero.

Questo cambia l'elenco a. Se si desidera conservare gli elenchi originali, è necessario utilizzare Concat(come indicato nelle altre risposte):

var newList = a.Concat(b);

Questo restituisce un IEnumerablefintanto che anon è nullo.


27
Nessuno ha mai pensato a quale metodo usare. AddRange modifica un elenco in atto, aggiungendo il secondo elenco (come se si chiamasse .Add (piè di pagina) più volte). I metodi di estensione Concat e Union non modificano l'elenco originale. Costruiscono pigramente un nuovo IEnumerable e non accederanno nemmeno ai membri dell'elenco originale se non necessario. Come notato, Union rimuove i duplicati mentre gli altri no.
ShawnFumo,

4
Qualcuno sa qual è la complessità di questo metodo? (È un peccato che Microsoft non fornisca queste informazioni importanti come parte del loro MSDN)
Jacob

2
Ti consiglio di verificare questo buon confronto tra i vari approcci. Mostra anche alcune analisi delle prestazioni di varie opzioni: Unisci raccolte
BogeyMan,

Funziona perfettamente. Stava usando concat () su oltre mezzo milione di articoli, il che ha richiesto diversi minuti. Questo approccio richiede meno di 5 secondi.
GreenFerret95,

111

Il modo con il minimo dispendio di spazio è utilizzare il metodo di estensione Concat.

var combined = list1.Concat(list2);

Crea un'istanza IEnumerable<T>che enumera gli elementi di list1 e list2 in quell'ordine.


2
ricordati di using System.Linq;essere in grado di usare Concat
tothemario il

43

Il metodo Union potrebbe rispondere alle tue esigenze. Non hai specificato se l'ordine o i duplicati erano importanti.

Prendi due IEnumerables ed esegui un'unione come mostrato qui:

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

Qualcosa come questo:

firstList.AddRange (secondList);

In alternativa, è possibile utilizzare il metodo di estensione "Union" definito in System.Linq. Con 'Unione', puoi anche specificare un comparatore, che può essere usato per specificare se un articolo deve essere unito o meno.

Come questo:

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

Funziona bene, penso di si. Come detto in precedenza, Concat restituisce una nuova sequenza e durante la conversione del risultato in Elenco, esegue perfettamente il lavoro. Le conversioni implicite possono non riuscire a volte quando si utilizza il metodo AddRange.


13

Se alcuni elementi sono presenti in entrambi gli elenchi, è possibile utilizzarli

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

7

Finché sono dello stesso tipo, è molto semplice 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 }

Mi piace anche questo Molto semplice. Grazie.
GurdeepS

Mi piace perché non muta nessuno dei due elenchi.
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

In un modo, non ho visto menzionato che può essere un po 'più robusto, in particolare se si desidera modificare ogni elemento in qualche modo (ad esempio, si voleva .Trim()tutti gli elementi.

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

1

Vedi questo link

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

// Ottieni i prodotti da entrambi gli array // esclusi i duplicati.

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

Le due opzioni che utilizzo sono:

list1.AddRange(list2);

o

list1.Concat(list2);

Tuttavia ho notato come ho usato che quando si utilizza il AddRangemetodo con una funzione ricorsiva, che si chiama molto spesso, ho ottenuto un'eccezione SystemOutOfMemoryException perché è stato raggiunto il numero massimo di dimensioni.

(Messaggio tradotto da Google)
Le dimensioni dell'array hanno superato l'intervallo supportato.

Utilizzando Concatrisolto quel problema.


0

Volevo solo testare come Unionfunziona con il comparatore predefinito su raccolte sovrapposte di oggetti del tipo di riferimento.

Il mio oggetto è:

class MyInt
{
    public int val;

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

Il mio codice di prova è:

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

L'output è:

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

Quindi, tutto funziona bene.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.