Joindre deux listes ensemble


333

Si j'ai deux listes de chaînes de type (ou tout autre type), quel est un moyen rapide de joindre les deux listes?

L'ordre doit rester le 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 lors de la recherche sur Google et je ne voulais pas implémenter d'interfaces .NET pour accélérer la livraison.


5
La commande est-elle importante? Voulez-vous conserver les doublons?
Larsenal

Réponses:


574

Tu pourrais essayer:

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

a.AddRange(b);

Page MSDN pour AddRange

Cela préserve l'ordre des listes, mais ne supprime pas les doublons qui Unionferaient l'affaire.

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

var newList = a.Concat(b);

Cela renvoie un IEnumerabletant que an'est pas nul.


27
Personne ne s'est vraiment demandé 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, sauf si cela est nécessaire. Comme indiqué, Union supprime les doublons, contrairement aux autres.
ShawnFumo

4
Quelqu'un sait-il quelle est la complexité de cette méthode? (Il est vraiment dommage que Microsoft ne fournisse pas ces informations importantes dans le cadre de leur MSDN)
Jacob

2
Je vous recommande de vérifier cette bonne comparaison des différentes approches. Afficher également une analyse des performances de diverses options: Fusionner les collections
BogeyMan

Cela fonctionne parfaitement. Utilisait concat () sur plus d'un demi-million d'éléments, ce qui prenait plusieurs minutes. Cette approche prend moins de 5 secondes.
GreenFerret95

111

Le moyen avec le moins d'espace supplémentaire est d'utiliser la méthode d'extension Concat.

var combined = list1.Concat(list2);

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


2
n'oubliez pas using System.Linq;de pouvoir utiliser Concat
tothemario

43

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

Prenez deux IEnumerables et effectuez une union comme indiqué 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 } 

24

Quelque chose comme ça:

firstList.AddRange (secondList);

Ou, vous pouvez utiliser la méthode d'extension «Union» définie 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 réuni ou non.

Comme ça:

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

Cela fonctionne bien, je pense que oui. Comme indiqué précédemment, Concat renvoie une nouvelle séquence et lors de la conversion du résultat en List, il fait parfaitement le travail. Les conversions implicites peuvent parfois échouer lors de l'utilisation de la méthode AddRange.


13

Si certains éléments existent dans les deux listes, vous pouvez utiliser

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

7

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

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

J'aime ça parce qu'il ne mute pas dans les deux listes.
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

D'une façon, je n'ai pas vu de mention qui peut être un peu plus robuste, en particulier si vous vouliez modifier chaque élément d'une certaine manière (par exemple, vous vouliez .Trim()tous les éléments.

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

1

Voir ce lien

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 deux tableaux // à l'exclusion des 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
*/

1

Les deux options que j'utilise sont:

list1.AddRange(list2);

ou

list1.Concat(list2);

Cependant, j'ai remarqué que lorsque j'utilisais la AddRangeméthode avec une fonction récursive, cela s'appelle très souvent, j'ai une SystemOutOfMemoryException car le nombre maximal de dimensions a été atteint.

(Message traduit par Google)
Les dimensions du tableau ont dépassé la plage prise en charge.

L'utilisation a Concatrésolu ce problème.


0

Je voulais juste tester le Unionfonctionnement du comparateur par défaut sur des collections qui se chevauchent 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

Donc, tout fonctionne bien.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.