別のリストからアイテムを削除する


206

別のアイテムのリストから削除したいアイテムの一般的なリストをトラバースする方法を見つけようとしています。

仮説の例としてこれを持っているとしましょう

List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();

foreachを使用してlist1をトラバースし、List2にも含まれているList1の各項目を削除します。

foreachはインデックスベースではないので、どうすればよいかよくわかりません。


1
List2にもあるList1のアイテムを削除しますか?
Srinivas Reddy Thatiparthy 2010

1
list1 = {foo1}およびlist2 = {foo1、foo1}の場合はどうなるでしょうか。foo1のすべてのコピーをlist2から削除する必要がありますか、それとも最初のコピーのみですか?
Mark Byers、

2
-1- すべて間違っていると思ったので、この質問のすべての回答に反対票を入れましたが、質問がひどく聞かれただけのようです。今、私はそれらを変更することはできません-謝罪。にlist1存在list2するアイテムを削除list2list1ますか、それともに存在するアイテムを削除しますか?このコメントの時点で、提供された各回答は後者を実行します。
John Rasch

7
@John Rashch、あなたはそれらの反対票に対して少し幸せなトリガーになるはずです。回答のいくつかはかなり概念的であり、質問で言及されたリストに関係することなく、OPが望むものを達成する方法を示すだけです。
ジョアン・アンジェロ

3
@Mark-正解です、私の責任です。それで、何が起こったのかを説明するコメントをここに載せました。投票後、同じような質問に対してすでに持っていた以前の回答を探していました。私がそれを見つけた後のコメント-これはこれにとって最良のプロセスではないことが判明!
John Rasch

回答:


358

Exceptを使用できます。

List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();
List<car> result = list2.Except(list1).ToList();

おそらくこれらの一時変数も必要ありません。

List<car> result = GetSomeOtherList().Except(GetTheList()).ToList();

ご了承ください Exceptどちらのリストも変更しないことにて。結果を含む新しいリストが作成されます。


13
マイナーポイントですが、これはを生成IEnumerable<car>List<car>ます。あなたToList()はリストを取り戻すために呼び出す必要があります。さらに、それはそうあるべきだと思いますGetSomeOtherList().Except(GetTheList()).ToList()
アダム・ロビンソン

9
using System.Linq;以前に持っていなかった場合にも必要になります。
yellavon 2015年

1
注:list1.Except(list2)は、list2.Except(list1)と同じ結果にはなりません。最後は私のために働きました。
radbyx

2
Exceptこれは実際にはセット操作を実行するため、使用するときは注意してください。これにより、結果のリストが区別されます。を使用しているためList、この動作を期待していませんでしたHashSet関連。
ローガン

4
どうしてこれが正しい答えなのですか?確かにこれはあなたの文脈であなたが望むものを与えるかもしれません、しかし、「別のリストからアイテムを削除する」は確かにセット差分演算と同等ではなく、これを正しい答えとして受け入れることで人々に誤解を与えてはいけません!!!!
user1935724 2016年

37

List<T>クラスではRemove関数を使用してインデックスではなく値でアイテムを削除できるため、インデックスは必要ありません。

foreach(car item in list1) list2.Remove(item);

3
+1、ただしIMOはlist2.Remove(item);ステートメントの前後にブラケットを使用する必要があります。
ANeves、2010

2
@sr pt:別の行に表示されるステートメントでは常に角かっこを使用しますが、フロー制御ステートメントと同じ行に配置できる/実行できない単一ステートメントのブロックでは使用しません。
Adam Robinson

4
@uriz:何がエレガントになるかの資格を無視して、これは実際に質問が言うことを実行する唯一の回答です(メインリストの項目を削除します)。他の答えは新しいリストを作成しますが、リストが、置換リストを取得する代わりに変更されることを期待している別の呼び出し元から渡されている場合は、望ましくない可能性があります。
アダムロビンソン

5
@uriz @AdamRobinsonエレガントなソリューションについて説明している...list1.ForEach(c => list2.Remove(c));
David Sherret 2014年

1
「エレガント」とは「開発者がこのコードの保守にこだわっているので、コードがシンプルで理解しやすくなる」という意味です。これが最良の答えです。
Seth

22

LINQ拡張メソッドの使用をお勧めします。次のような1行のコードで簡単に実行できます。

list2 = list2.Except(list1).ToList();

これはもちろん、list2から削除するlist1のオブジェクトが同じインスタンスであることを前提としています。


2
重複も削除されます。
7

17

私の場合、外部キーのような共通の識別子を持つ2つの異なるリストがありました。「nzrytmn」が引用する2番目のソリューション:

var result =  list1.Where(p => !list2.Any(x => x.ID == p.ID && x.property1 == p.property1)).ToList();

私の状況に最も適したものでした。すでに登録されているレコードなしでDropDownListをロードする必要がありました。

ありがとうございました !!!

これは私のコードです:

t1 = new T1();
t2 = new T2();

List<T1> list1 = t1.getList();
List<T2> list2 = t2.getList();

ddlT3.DataSource= list2.Where(s => !list1.Any(p => p.Id == s.ID)).ToList();
ddlT3.DataTextField = "AnyThing";
ddlT3.DataValueField = "IdAnyThing";
ddlT3.DataBind();

OUはDDlT3が何であったか説明したことがない
rogue39nin

15

LINQを使用することもできますが、私はRemoveAllメソッドを使用します。それがあなたの意図をよりよく表すものだと思います。

var integers = new List<int> { 1, 2, 3, 4, 5 };

var remove = new List<int> { 1, 3, 5 };

integers.RemoveAll(i => remove.Contains(i));

9
または、あなたができるメソッドグループでさらに簡単です-integers.RemoveAll(remove.Contains);
ライアン

12
list1.RemoveAll(l => list2.Contains(l));

別名「完全に不純」:-)
Xan-Kun Clark-Davis

どうしたの。Exceptを使用して別のリストを作成するよりも見栄えがします。特に両方のリストが非常に小さい場合。
マイクケスキノフ2018年

1
どちらのリストメソッドもであるためO(N)、これはO(N^2)大きなリストで問題になる可能性があります。
tigrou

7

解決策1:次のようにすることができます。

List<car> result = GetSomeOtherList().Except(GetTheList()).ToList();

ただし、このソリューションが機能しない場合もあります。それがうまくいかない場合は、私の2番目のソリューションを使用できます。

解決策2:

List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();

list1がメインリストで、list2が二次リストであり、list2のアイテムなしでlist1のアイテムを取得したいとします。

 var result =  list1.Where(p => !list2.Any(x => x.ID == p.ID && x.property1 == p.property1)).ToList();

0

Exceptリストを変更しない、あなたが使用できるのForEachをList<T>

list2.ForEach(item => list1.Remove(item));

それは最も効率的な方法ではないかもしれませんが、それは簡単で、それゆえ読みやすく、そしてそれは元のリストを更新します(これは私の要件です)。


-3

ほら。

    List<string> list = new List<string>() { "1", "2", "3" };
    List<string> remove = new List<string>() { "2" };

    list.ForEach(s =>
        {
            if (remove.Contains(s))
            {
                list.Remove(s);
            }
        });

3
-1。これは、最初のアイテムが削除された後に例外をスローします。また、(通常)リストを走査してremove削除することをお勧めします。これは通常、サイズが小さいためです。また、この方法でリストトラバーサルを強制的に実行します。
Adam Robinson
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.