2

リストが 1 つあるとします。

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

そして別のリスト...

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

次のように originalList を更新するにはどうすればよいですか。

  1. int が newList に表示される場合は、保持します
  2. int が newList に表示されない場合は、削除します
  3. newList からの ints を originalList に追加しますが、まだそこにはありません

したがって、originalList の内容を作成します。

{ 1, 5, 7, 11 }

私が尋ねている理由は、子のコレクションを持つオブジェクトがあるからです。ユーザーがこのコレクションを更新するとき、すべての子を削除してから選択を挿入するのではなく、コレクション全体を破棄して挿入するのではなく、追加または削除された子に対処した方が効率的だと思います。 newList の子は、それらがすべて新しいものであるかのように表示されます。

編集 - 申し訳ありませんが、ひどいタイトルを書きました...「効率的」ではなく「コードの最小量」と書くべきでした。それは私が得た多くの答えを捨てたと思います。それらはすべて素晴らしいです...ありがとう!

4

10 に答える 10

5
originalList = newList;

または、それらを個別のリストにしたい場合:

originalList = new List<int>(newList);

しかし、どちらの方法でもあなたが望むことをします。ルールにより、更新後、originalList は newList と同じになります。

更新:この回答を支持していただきありがとうございますが、質問をよく読んだ後、私の他の回答(以下)が正しいと思います。

于 2008-09-29T13:41:54.287 に答える
2

LINQ 拡張メソッドを使用する場合は、次の 2 行で実行できます。

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

これは、元のオブジェクトで Equals をオーバーライドしたことを前提としています (他の人のソリューションと同様)。しかし、何らかの理由で Equals をオーバーライドできない場合は、次のように IEqualityOperator を作成できます。

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

次に、上記の行は次のようになります。

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

とにかく IEqualityOperator を渡す場合は、2 行目をさらに短くすることができます。

originalList.RemoveAll(x => !newList.Contains(x, new EqualThingTester()));
originalList.AddRange(newList.Except(originalList, new EqualThingTester()));
于 2008-09-29T16:01:56.663 に答える
1

申し訳ありませんが、最後の段落を見る前に最初の応答を書きました。

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);
}
于 2008-09-29T13:49:16.937 に答える
1

最終的な順序について心配していない場合は、Hashtable/HashSet がおそらく最も高速です。

于 2008-09-29T13:50:00.147 に答える
1

LINQ ソリューション:

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);
于 2008-09-29T13:50:41.423 に答える
0

これは、開発者が多対多のデー​​タベース関係を維持する UI を作成するときに遭遇する一般的な問題です。これがどれほど効率的かはわかりませんが、このシナリオを処理するヘルパー クラスを作成しました。

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

}
于 2008-09-29T14:11:00.720 に答える
0
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);
  }
}

あまりきれいではありませんが、機能します。

于 2008-09-29T13:48:04.177 に答える
0

これを行うための組み込みの方法はありません。私が考えることができる最も近い方法は、DataTableが新しい項目と削除された項目を処理する方法です。

@James Curranが提案しているのは、originalList オブジェクトを newList オブジェクトに置き換えるだけです。oldList をダンプしますが、変数は保持します (つまり、ポインターはまだそこにあります)。

いずれにせよ、これを最適化することが有効な時間であるかどうかを検討する必要があります。あるリストから次のリストに値をコピーするのに費やされる実行時間の大部分は、それだけの価値があるかもしれません。そうではなく、時期尚早の最適化を行っている場合は、無視する必要があります。

最適化を開始する前に、GUI の改良やアプリケーションのプロファイリングに時間を費やしてください。

于 2008-09-29T13:51:20.410 に答える
0

私の最初の考えは、 originalList.AddRange(newList) を呼び出してから重複を削除できるということでしたが、リストをクリアして再作成するよりも効率的かどうかはわかりません。

于 2008-09-29T13:44:08.057 に答える
0

.Net 3.5を使用している場合

var List3 = List1.Intersect(List2);

2 つのリストの共通部分を含む新しいリストを作成します。これが、ここで狙っていると思われるものです。

于 2008-09-29T17:17:13.300 に答える