Was ist die geringste Menge an Code benötigt, um eine Liste mit einer anderen Liste zu aktualisieren?

StackOverflow https://stackoverflow.com/questions/148662

Frage

Angenommen, ich habe eine Liste:

IList<int> originalList = new List<int>();
originalList.add(1);
originalList.add(5);
originalList.add(10);

Und eine andere Liste ...

IList<int> newList = new List<int>();
newList.add(1);
newList.add(5);
newList.add(7);  
newList.add(11);

Wie kann ich aktualisieren Originalliste, so dass:

  1. Wenn die int in newList erscheint, halten
  2. Wenn die int in newList nicht erscheint, entfernen
  3. Fügen Sie alle ints von newList in Originalliste, die bereits nicht da sind

So - machen den Inhalt der Originalliste:

{ 1, 5, 7, 11 }

Der Grund, warum ich frage ist, weil ich ein Objekt mit einer Sammlung von Kindern habe. Wenn der Benutzer diese Sammlung aktualisiert, anstatt nur alle Kinder zu löschen, dann ihre Auswahl einfügen, glaube, ich würde es effizienter sein, wenn ich nur auf die Kinder gehandelt, die hinzugefügt oder entfernt wurden, anstatt zu reißen die ganze Sammlung nach unten, und das Einsetzen der newList Kinder, als ob sie alle neu sind.

EDIT - Sorry - ich schrieb einen schrecklichen Titel ... ich geschrieben ‚geringste Menge an Code‘ anstelle von ‚effizient‘ sein sollte. Ich denke, dass eine Menge der Antworten warf ich bekommen habe. Sie sind alle großen ... Danke!

War es hilfreich?

Lösung

Sorry, schrieb meine erste Antwort, bevor ich deinen letzten Absatz sah.

for(int i = originalList.length-1; i >=0; --i)
{
     if (!newList.Contains(originalList[i])
            originalList.RemoveAt(i);
}

foreach(int n in newList)
{
     if (!originaList.Contains(n))
           originalList.Add(n);
}

Andere Tipps

originalList = newList;

Oder wenn Sie es vorziehen, sie verschiedene Listen zu sein:

originalList = new List<int>(newList);

Aber, so oder so tut, was Sie wollen. Durch Ihre Regeln, nach der Aktualisierung wird auf Originalliste newList identisch sein.

UPDATE:. Ich danke euch allen für die Unterstützung dieser Antwort, aber nach einer genaueren Lektüre der Frage, ich glaube, meine andere Antwort (unten) ist die richtige

Wenn Sie einige LINQ-Erweiterungsmethoden verwenden, können Sie es in zwei Linien tun können:

originalList.RemoveAll(x => !newList.Contains(x));
originalList.AddRange(newList.Where(x => !originalList.Contains(x)));

Dies setzt voraus, (wie andere Menschen Lösungen zu tun), dass Sie Equals in Ihrem ursprünglichen Objekt außer Kraft gesetzt haben. Aber wenn Sie nicht Equals aus irgendeinem Grund außer Kraft setzen kann, können Sie eine IEqualityOperator wie folgt erstellen:

class EqualThingTester : IEqualityComparer<Thing>
{
    public bool Equals(Thing x, Thing y)
    {
        return x.ParentID.Equals(y.ParentID);
    }

    public int GetHashCode(Thing obj)
    {
        return obj.ParentID.GetHashCode();
    }
}

Dann werden die obigen Zeilen werden:

originalList.RemoveAll(x => !newList.Contains(x, new EqualThingTester()));
originalList.AddRange(newList.Where(x => !originalList.Contains(x, new EqualThingTester())));

Und wenn Sie in einem IEqualityOperator sowieso vorbei sind, können Sie die zweite Zeile noch kürzer machen:

originalList.RemoveAll(x => !newList.Contains(x, new EqualThingTester()));
originalList.AddRange(newList.Except(originalList, new EqualThingTester()));

Wenn Sie nicht besorgt über die eventuelle Bestellung sind, ein Hashtable / HashSet wird wahrscheinlich die schnellste sein.

LINQ Lösung:

originalList = new List<int>(
                      from x in newList
                      join y in originalList on x equals y into z
                      from y in z.DefaultIfEmpty()
                      select x);

Mein erster Gedanke war, dass man originalList.AddRange (newList) und entfernen Sie die Duplikate nennen könnte -. Aber ich bin mir nicht sicher, ob die ein effizient wäre als die Liste Clearing- und repopulating es

List<int> firstList = new List<int>() {1, 2, 3, 4, 5};
List<int> secondList = new List<int>() {1, 3, 5, 7, 9};

List<int> newList = new List<int>();

foreach (int i in firstList)
{
  newList.Add(i);
}

foreach (int i in secondList)
{
  if (!newList.Contains(i))
  {
    newList.Add(i);
  }
}

Nicht sehr sauber -. Aber es funktioniert

Es gibt keine Art und Weise in dies zu tun gebaut, in der Nähe ich denken kann, ist die Art und Weise Datatable neue und gelöschte Elemente behandelt.

Was @James Curran schlägt vor, lediglich das Originalliste Objekt mit dem newList Objekt zu ersetzen. Es wird die oldList Dump, aber halten Sie die Variable (das heißt der Zeiger ist immer noch da).

Egal, sollten Sie prüfen, ob diese Optimierung Zeit ist gut angelegt. Ist die Mehrheit der Laufzeitwerte von einer Liste in die nächste verbrachte kopieren, könnte es sich lohnen. Wenn es nicht ist, sondern etwas verfrüht Optimierung Sie tun, sollten Sie es ignorieren.

Verbringen Sie Zeit, um die GUI Polieren oder das Anwendungsprofil, bevor Sie Optimierung starten ist meine $ .02.

Dies ist ein weit verbreitetes Problem Entwickler in denen UIs Schreiben many-to-many-Datenbank Beziehungen aufrecht zu erhalten. Ich weiß nicht, wie effizient das ist, aber ich schrieb eine Hilfsklasse dieses Szenario zu behandeln:

public class IEnumerableDiff<T>
{
    private delegate bool Compare(T x, T y);

    private List<T> _inXAndY;
    private List<T> _inXNotY;
    private List<T> _InYNotX;

    /// <summary>
    /// Compare two IEnumerables.
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="compareKeys">True to compare objects by their keys using Data.GetObjectKey(); false to use object.Equals comparison.</param>
    public IEnumerableDiff(IEnumerable<T> x, IEnumerable<T> y, bool compareKeys)
    {
        _inXAndY = new List<T>();
        _inXNotY = new List<T>();
        _InYNotX = new List<T>();
        Compare comparer = null;
        bool hit = false;

        if (compareKeys)
        {
            comparer = CompareKeyEquality;
        }
        else
        {
            comparer = CompareObjectEquality;
        }


        foreach (T xItem in x)
        {
            hit = false;
            foreach (T yItem in y)
            {
                if (comparer(xItem, yItem))
                {
                    _inXAndY.Add(xItem);
                    hit = true;
                    break;
                }
            }
            if (!hit)
            {
                _inXNotY.Add(xItem);
            }
        }

        foreach (T yItem in y)
        {
            hit = false;
            foreach (T xItem in x)
            {
                if (comparer(yItem, xItem))
                {
                    hit = true;
                    break;
                }
            }
            if (!hit)
            {
                _InYNotX.Add(yItem);
            }
        }
    }

    /// <summary>
    /// Adds and removes items from the x (current) list so that the contents match the y (new) list.
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="compareKeys"></param>
    public static void SyncXList(IList<T> x, IList<T> y, bool compareKeys)
    {
        var diff = new IEnumerableDiff<T>(x, y, compareKeys);
        foreach (T item in diff.InXNotY)
        {
            x.Remove(item);
        }
        foreach (T item in diff.InYNotX)
        {
            x.Add(item);
        }
    }

    public IList<T> InXAndY
    {
        get { return _inXAndY; }
    }

    public IList<T> InXNotY
    {
        get { return _inXNotY; }
    }

    public IList<T> InYNotX
    {
        get { return _InYNotX; }
    }

    public bool ContainSameItems
    {
        get { return _inXNotY.Count == 0 && _InYNotX.Count == 0; }
    }

    private bool CompareObjectEquality(T x, T y)
    {
        return x.Equals(y);
    }

    private bool CompareKeyEquality(T x, T y)
    {
        object xKey = Data.GetObjectKey(x);
        object yKey = Data.GetObjectKey(y);
        return xKey.Equals(yKey);
    }

}

wenn Ihr mit .Net 3.5

var List3 = List1.Intersect(List2);

Erstellt eine neue Liste, die den Schnittpunkt der beiden Listen enthält, das ist, was ich glaube, Sie hier schießen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top