2009-10-06 13 views
220

Si j'ai deux listes de type string (ou tout autre type), comment joindre rapidement les deux listes?Joindre deux listes ensemble

La commande doit rester la même. Les doublons doivent être supprimés (bien que chaque élément des deux liens soit unique). Je n'ai pas trouvé grand chose à ce sujet quand googling et je ne voulais pas implémenter des interfaces .NET pour la rapidité de livraison.

+4

L'ordre est-il important? Voulez-vous conserver les doublons? – Larsenal

+1

Possible duplicate of * [Comment concaténer les listes en C#?] (Http://stackoverflow.com/questions/1042219/how-do-you-concatenate-lists-in-c) *. –

Répondre

380

Vous pouvez essayer:

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

a.AddRange(b); 

MSDN page for AddRange

Cela préserve l'ordre des listes, mais il ne supprime pas les doublons qui Union ferait .

Cela change la liste a. Si vous voulez conserver les listes originales, vous devez utiliser Concat (comme indiqué dans les autres réponses):

var newList = a.Concat(b); 

Ce retourne un IEnumerable tant que a est non nul.

+13

Personne n'est vraiment allé quand utiliser quelle méthode. AddRange édite une liste en place, en y ajoutant la deuxième liste (comme si vous appeliez .Add (foo) plusieurs fois). Les méthodes d'extension Concat et Union ne modifient pas la liste d'origine. Ils construisent paresseusement un nouvel IEnumerable et n'accèdent même pas aux membres de la liste d'origine à moins que cela ne soit nécessaire. Comme indiqué, Union supprime les doublons alors que les autres ne le font pas. – ShawnFumo

+2

'concat' ne fonctionne pas lorsque l'une des listes est nulle – Amit

+3

Est-ce que quelqu'un sait quelle est la complexité de cette méthode? (Il est tellement honteux que Microsoft ne fournisse pas cette information importante dans le cadre de leur MSDN) – Jacob

19

Quelque chose comme ceci:

firstList.AddRange (secondList); 

Ou, vous pouvez utiliser la méthode d'extension 'Union' qui est défini dans System.Linq. Avec 'Union', vous pouvez également spécifier un comparateur, qui peut être utilisé pour spécifier si un élément doit être uni ou non.

Comme ceci:

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

La méthode Union peut répondre à vos besoins. Vous n'avez pas précisé si l'ordre ou les doublons étaient importants.

Prenez deux IEnumerables et effectuer une union comme on le voit ici:

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

une façon: List.AddRange() en fonction des types?

85

Le moyen le moins au-dessus de l'espace est d'utiliser la méthode d'extension Concat.

var combined = list1.Concat(list2); 

Il crée une instance de IEnumerable<T> qui énumère les éléments de list1 et list2 dans cet ordre.

7

Tant qu'ils sont du même type, il est très simple avec 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

J'aime ça aussi. Très simple. Merci. – dotnetdev

+0

J'aime ça parce qu'il ne mute aucune de ces listes. –

10

Si certains article (s) sont disponibles dans les deux listes que vous pouvez utiliser

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

Cela fonctionne très bien, je le pense. Comme dit précédemment, Concat retourne une nouvelle séquence et tout en convertissant le résultat en List, il fait parfaitement le travail. Les conversions implicites peuvent échouer parfois lors de l'utilisation de la méthode AddRange.

1

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

// Obtenez les produits des tableaux les deux // excluant les doublons.

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

Je voulais juste tester comment Union fonctionne avec le comparateur par défaut sur chevauchement des collections d'objets de type référence.

Mon objet est:

class MyInt 
{ 
    public int val; 

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

Mon code de test est:

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

La sortie est:

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 

Ainsi, tout fonctionne très bien.

Questions connexes