Zwei Listen zusammenfügen


333

Wenn ich zwei Listen mit Typzeichenfolge (oder einem anderen Typ) habe, wie kann ich die beiden Listen schnell verbinden?

Die Bestellung sollte gleich bleiben. Duplikate sollten entfernt werden (obwohl jedes Element in beiden Links eindeutig ist). Ich habe beim Googeln nicht viel darüber gefunden und wollte keine .NET-Schnittstellen implementieren, um die Zustellung zu beschleunigen.


5
Ist die Bestellung wichtig? Möchten Sie Duplikate behalten?
Larsenal

Antworten:


572

Du könntest es versuchen:

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

a.AddRange(b);

MSDN-Seite für AddRange

Dadurch bleibt die Reihenfolge der Listen erhalten, es werden jedoch keine Duplikate entfernt, die Uniondies tun würden.

Dies ändert die Liste a. Wenn Sie die ursprünglichen Listen beibehalten möchten, sollten Sie Folgendes verwenden Concat(wie in den anderen Antworten angegeben):

var newList = a.Concat(b);

Dies gibt ein zurück IEnumerable, solange aes nicht null ist.


27
Niemand hat wirklich darüber nachgedacht, wann er welche Methode anwenden soll. AddRange bearbeitet eine Liste an Ort und Stelle und fügt die zweite Liste hinzu (als hätten Sie mehrmals .Add (foo) aufgerufen). Die Concat- und Union-Erweiterungsmethoden ändern die ursprüngliche Liste nicht. Sie erstellen träge eine neue IEnumerable und greifen nicht einmal auf die ursprünglichen Listenmitglieder zu, es sei denn, dies ist erforderlich. Wie bereits erwähnt, entfernt Union Duplikate, während die anderen dies nicht tun.
ShawnFumo

4
Weiß jemand, wie komplex diese Methode ist? (Es ist so schade, dass Microsoft diese wichtigen Informationen nicht als Teil ihres MSDN bereitstellt.)
Jacob

2
Ich empfehle Ihnen, diesen guten Vergleich der verschiedenen Ansätze zu überprüfen. Zeigen Sie auch einige Leistungsanalysen verschiedener Optionen: Sammlungen zusammenführen
BogeyMan

Das funktioniert perfekt. Verwendete concat () für mehr als eine halbe Million Artikel, was einige Minuten dauerte. Dieser Ansatz dauert weniger als 5 Sekunden.
GreenFerret95

110

Der Weg mit dem geringsten Speicherplatzaufwand ist die Verwendung der Concat-Erweiterungsmethode.

var combined = list1.Concat(list2);

Es wird eine Instanz erstellt, von IEnumerable<T>der die Elemente von list1 und list2 in dieser Reihenfolge aufgelistet werden.


2
using System.Linq;Denken
Sie

43

Die Union- Methode kann auf Ihre Bedürfnisse eingehen. Sie haben nicht angegeben, ob Reihenfolge oder Duplikate wichtig sind.

Nehmen Sie zwei IEnumerables und führen Sie eine Vereinigung durch, wie hier gezeigt:

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

Etwas wie das:

firstList.AddRange (secondList);

Sie können auch die in System.Linq definierte Erweiterungsmethode 'Union' verwenden. Mit 'Vereinigung' können Sie auch einen Vergleicher angeben, mit dem festgelegt werden kann, ob ein Element vereinigt werden soll oder nicht.

So was:

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

Es funktioniert gut, denke ich. Wie bereits erwähnt, gibt Concat eine neue Sequenz zurück und erledigt das Ergebnis perfekt, während es das Ergebnis in List konvertiert. Implizite Konvertierungen können manchmal fehlschlagen, wenn die AddRange-Methode verwendet wird.


13

Wenn in beiden Listen einige Elemente vorhanden sind, können Sie diese verwenden

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

7

Solange sie vom gleichen Typ sind, ist es mit AddRange sehr einfach:

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 }

Ich mag das auch. Sehr einfach. Vielen Dank.
GurdeepS

Ich mag das, weil es keine der beiden Listen mutiert.
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

Eine Möglichkeit, die ich nicht erwähnt habe, kann etwas robuster sein, insbesondere wenn Sie jedes Element auf irgendeine Weise ändern möchten (z. B. wenn Sie .Trim()alle Elemente ändern möchten.

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

1

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

// Holen Sie sich die Produkte von beiden Arrays // ohne Duplikate.

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

Die zwei Optionen, die ich benutze, sind:

list1.AddRange(list2);

oder

list1.Concat(list2);

Allerdings habe ich bemerkt, wie ich das bei der Verwendung der verwendet habe AddRange Methode mit einer rekursiven Funktion, die sich sehr oft selbst aufruft, ist , dass ich eine SystemOutOfMemoryException erhalten habe, da die maximale Anzahl von Dimensionen erreicht wurde.

(Nachricht Google Translated)
Die Array-Abmessungen haben den unterstützten Bereich überschritten.

Mit hat Concatdieses Problem gelöst.


0

Ich wollte nur testen wie Union mit dem Standardvergleicher überlappende Sammlungen von Objekten vom Referenztyp funktionieren.

Mein Objekt ist:

class MyInt
{
    public int val;

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

Mein Testcode lautet:

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

Die Ausgabe ist:

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

Also funktioniert alles gut.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.