it-swarm.com.de

Der schnellste Weg, um zwei Listen <> zu vergleichen

Was ist der schnellste (und am wenigsten ressourcenintensive) Vergleich zweier massiver (> 50.000 Elemente) und als Ergebnis zwei Listen wie die folgende:

  1. elemente, die in der ersten Liste angezeigt werden, jedoch nicht in der zweiten
  2. elemente, die in der zweiten Liste angezeigt werden, jedoch nicht in der ersten Liste

Derzeit arbeite ich mit List oder IReadOnlyCollection und löse dieses Problem in einer Linq-Abfrage:

var list1 = list.Where(i => !list2.Contains(i)).ToList();
var list2 = list2.Where(i => !list.Contains(i)).ToList();

Aber das ist nicht so gut, wie ich es gerne hätte ... Eine Idee, dies schneller und weniger ressourcenintensiv zu machen, da ich viele Listen bearbeiten muss?

164
Frank

Verwenden Sie Except :

var firstNotSecond = list1.Except(list2).ToList();
var secondNotFirst = list2.Except(list1).ToList();

Ich vermute, dass es Ansätze gibt, die tatsächlich geringfügig schneller wären als diese, aber selbst dies wird sehr _ schneller als Ihr O (N * M) -Ansatz.

Wenn Sie diese kombinieren möchten, können Sie eine Methode mit den oben genannten und dann eine return-Anweisung erstellen:

return !firstNotSecond.Any() && !secondNotFirst.Any();
343
Jon Skeet

Effizienter wäre die Verwendung von Enumerable.Except :

var inListButNotInList2 = list.Except(list2);
var inList2ButNotInList = list2.Except(list);

Diese Methode wird implementiert, indem die verzögerte Ausführung verwendet wird. Das heißt, Sie könnten zum Beispiel schreiben:

var first10 = inListButNotInList2.Take(10);

Es ist auch effizient, da es intern einen Set<T> verwendet, um die Objekte zu vergleichen. Dazu werden zunächst alle unterschiedlichen Werte aus der zweiten Sequenz gesammelt und dann die Ergebnisse der ersten Sequenz gestreamt, um zu überprüfen, dass sie noch nicht gesehen wurden.

32
Rango

Wenn Sie möchten, dass die Ergebnisse unabhängig von der GroßKleinschreibung -/sind, funktioniert Folgendes:

List<string> list1 = new List<string> { "a.dll", "b1.dll" };
List<string> list2 = new List<string> { "A.dll", "b2.dll" };

var firstNotSecond = list1.Except(list2, StringComparer.OrdinalIgnoreCase).ToList();
var secondNotFirst = list2.Except(list1, StringComparer.OrdinalIgnoreCase).ToList();

firstNotSecond würde b1.dll enthalten

secondNotFirst würde b2.dll enthalten

8
e.gad

Nicht für dieses Problem, aber hier ist etwas Code, um Listen für gleich und nicht zu vergleichen! identische Objekte: 

public class EquatableList<T> : List<T>, IEquatable<EquatableList<T>> where    T : IEquatable<T>

/// <summary>
/// True, if this contains element with equal property-values
/// </summary>
/// <param name="element">element of Type T</param>
/// <returns>True, if this contains element</returns>
public new Boolean Contains(T element)
{
    return this.Any(t => t.Equals(element));
}

/// <summary>
/// True, if list is equal to this
/// </summary>
/// <param name="list">list</param>
/// <returns>True, if instance equals list</returns>
public Boolean Equals(EquatableList<T> list)
{
    if (list == null) return false;
    return this.All(list.Contains) && list.All(this.Contains);
}
5
Pius Hermit

versuchen Sie es so:

var difList = list1.Where(a => !list2.Any(a1 => a1.id == a.id))
            .Union(list2.Where(a => !list1.Any(a1 => a1.id == a.id)));
2
Ali Issa

Ich habe diesen Code verwendet, um zwei Listen mit Millionen Datensätzen zu vergleichen.

Diese Methode wird nicht lange dauern

    //Method to compare two list of string
    private List<string> Contains(List<string> list1, List<string> list2)
    {
        List<string> result = new List<string>();

        result.AddRange(list1.Except(list2, StringComparer.OrdinalIgnoreCase));
        result.AddRange(list2.Except(list1, StringComparer.OrdinalIgnoreCase));

        return result;
    }
1
Sathish

Wenn nur ein kombiniertes Ergebnis benötigt wird, funktioniert dies auch:

var set1 = new HashSet<T>(list1);
var set2 = new HashSet<T>(list2);
var areEqual = set1.SetEquals(set2);

wobei T der Typ des Listenelements ist.

Enumerable.SequenceEqual-Methode

Legt fest, ob zwei Sequenzen gemäß einem Gleichheitsvergleich gleich sind. MS.Docs

Enumerable.SequenceEqual(list1, list2);

Dies funktioniert für alle primitiven Datentypen. Wenn Sie es für benutzerdefinierte Objekte verwenden müssen, müssen Sie IEqualityComparer implementieren.

Definiert Methoden zur Unterstützung des Vergleichs von Objekten auf Gleichheit.

IEqualityComparer-Schnittstelle

Definiert Methoden zur Unterstützung des Vergleichs von Objekten auf Gleichheit. MS.Docs für IEqualityComparer

0
miguelmpn
using System.Collections.Generic;
using System.Linq;

namespace YourProject.Extensions
{
    public static class ListExtensions
    {
        public static bool SetwiseEquivalentTo<T>(this List<T> list, List<T> other)
            where T: IEquatable<T>
        {
            if (list.Except(other).Any())
                return false;
            if (other.Except(list).Any())
                return false;
            return true;
        }
    }
}

Manchmal müssen Sie nur wissen, dass if zwei Listen unterschiedlich sind und nicht, was diese Unterschiede sind. In diesem Fall sollten Sie diese Erweiterungsmethode Ihrem Projekt hinzufügen. Beachten Sie, dass Ihre aufgelisteten Objekte IEquatable implementieren sollten!

Verwendungszweck:

public sealed class Car : IEquatable<Car>
{
    public Price Price { get; }
    public List<Component> Components { get; }

    ...
    public override bool Equals(object obj)
        => obj is Car other && Equals(other);

    public bool Equals(Car other)
        => Price == other.Price
            && Components.SetwiseEquivalentTo(other.Components);

    public override int GetHashCode()
        => Components.Aggregate(
            Price.GetHashCode(),
            (code, next) => code ^ next.GetHashCode()); // Bitwise XOR
}

Was auch immer die Component-Klasse ist, die hier für Car gezeigten Methoden sollten fast identisch implementiert werden.

Es ist sehr wichtig zu wissen, wie wir GetHashCode geschrieben haben. Um IEquatable ordnungsgemäß zu implementieren, bearbeiten Equals und GetHashCodemust die Eigenschaften der Instanz logisch kompatibel. 

Zwei Listen mit gleichem Inhalt sind immer noch unterschiedliche Objekte und erzeugen unterschiedliche Hash-Codes. Da wir möchten, dass diese beiden Listen als gleich behandelt werden, muss GetHashCode für jede von ihnen den gleichen Wert erzeugen. Wir können dies erreichen, indem wir den Hashcode an jedes Element in der Liste delegieren und den bitweisen Standard XOR verwenden, um alle zu kombinieren. XOR ist auftragsunabhängig, es ist also egal, ob die Listen anders sortiert sind. Es ist nur wichtig, dass sie nur gleichwertige Mitglieder enthalten.

Hinweis: Der seltsame Name soll bedeuten, dass die Methode die Reihenfolge der Elemente in der Liste nicht berücksichtigt. Wenn Sie sich um die Reihenfolge der Elemente in der Liste kümmern, ist diese Methode nicht für Sie!

0
Devon Parsons