2009-10-06 25 views
220

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

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

+4

L'ordine è importante? Vuoi conservare i duplicati? – Larsenal

+1

Eventuali duplicati di * [Come si fa a concatenare liste in C#?] (Http://stackoverflow.com/questions/1042219/how-do-you-concatenate-lists-in-c) *. –

risposta

380

si potrebbe provare:

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

a.AddRange(b); 

MSDN page for AddRange

Ciò preserva l'ordine degli elenchi, ma non rimuove i duplicati che Union farebbe .

Ciò modifica l'elenco a. Se si voleva conservare le liste originali allora si dovrebbe usare Concat (come sottolineato nelle altre risposte):

var newList = a.Concat(b); 

Ciò restituisce un IEnumerable finché a non è nullo.

+13

Nessuno se ne è veramente occupato quando utilizzare il metodo. AddRange modifica una lista, aggiungendo la seconda lista (come se si chiamasse .Add (foo) un mucchio di volte). I metodi di estensione Concat e Union non modificano l'elenco originale. Costruiscono pigramente un nuovo IEnumerable e non accedono nemmeno ai membri della lista originale, a meno che non sia necessario. Come notato, l'Unione rimuove i duplicati mentre gli altri no. – ShawnFumo

+2

'concat' non funziona quando una delle liste è nulle – Amit

+3

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

19

Qualcosa di simile a questo:

firstList.AddRange (secondList); 

In alternativa, è possibile utilizzare il metodo di estensione 'Unione' che si definisce in System.Linq. Con "Unione", è anche possibile specificare un comparatore, che può essere utilizzato per specificare se un elemento deve essere unito o meno.

Ti piace questa:

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 
34

Il metodo Union può soddisfare le vostre esigenze. Non hai specificato se l'ordine o i duplicati erano importanti.

prendere due IEnumerables ed eseguire un sindacato come si vede 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 } 
3

un modo: List.AddRange() a seconda del tipo?

85

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

var combined = list1.Concat(list2); 

crea un'istanza di IEnumerable<T> che enumerare gli elementi di lista1 e lista2 in questo ordine.

7

Finché sono dello stesso tipo, è molto semplice con AddRange:

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

Mi piace anche questo. Molto semplice. Grazie. – dotnetdev

+0

Mi piace perché non modifica la lista. –

10

Se qualche elemento (s) esiste in entrambe le liste è possibile utilizzare

var all = list1.Concat(list2).Concat(list3) ... Concat(listN).Distinct().ToList(); 
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); 
12
targetList = list1.Concat(list2).ToList(); 

sta funzionando bene penso di sì. Come detto in precedenza, Concat restituisce una nuova sequenza e mentre converte il risultato in List, fa perfettamente il lavoro. Le conversioni implicite potrebbero non riuscire a volte quando si utilizza il metodo AddRange.

1

Vai a questa 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 } }; 

// ottenere i prodotti dagli array entrambi // 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 
*/ 
0

Volevo solo verificare come Union opere con l'operatore di confronto di default sul sovrapposti collezioni di oggetti di tipo di riferimento.

Il mio scopo è:

class MyInt 
{ 
    public int val; 

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

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.