한 목록에서 다른 목록의 항목 제거


206

다른 항목 목록에서 제거하려는 일반 항목 목록을 탐색하는 방법을 알아 내려고합니다.

가설의 예로 이것을 가지고 있다고합시다.

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

foreach로 list1을 순회하고 List2에 포함 된 List1의 각 항목을 제거하고 싶습니다.

foreach는 색인 기반이 아니기 때문에 어떻게 해야할지 잘 모르겠습니다.


1
List2에있는 List1의 항목을 제거 하시겠습니까?
Srinivas Reddy Thatiparthy

1
list1 = {foo1} 및 list2 = {foo1, foo1}이 있으면 어떻게됩니까? foo1의 모든 사본을 list2에서 제거해야합니까, 아니면 첫 번째 만 제거해야합니까?
Mark Byers

2
-1-이 질문에 대한 모든 답변을 모두 틀렸다고 생각 했기 때문에 질문에 답 하지 않았습니다. 이제는 변경할 수 없습니다-사과합니다. 당신이에서 항목을 제거하겠습니까 list1에서 그 존재 list2, 또는에서 항목 제거 하시겠습니까 list2에서 그 존재를 list1? 이 의견을 제출할 때 제공된 각 답변이 후자를 수행합니다.
John Rasch

7
@ John Rashch, 당신은 그 downvotes에 대해 조금 덜 행복해야합니다. 일부 답변은 상당히 개념적이며 질문에 언급 된 목록과 관련되지 않고 OP가 원하는 것을 달성하는 방법 만 보여줍니다.
João Angelo

3
@ Mark-당신 말이 옳아 요. 내 잘못이 바로 여기에 내가 일어난 일을 설명하는 의견을 올리는 이유입니다. 나는 투표 후 그 동안 비슷한 질문에 대해 이미 답변을 받았고 떠날 예정이었습니다. 내가 그것을 찾은 후에 의견-이것이 최선의 과정이 아니라는 것이 밝혀졌습니다!
John Rasch

답변:


358

다음을 제외하고 사용할 수 있습니다 .

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()
Adam Robinson

9
using System.Linq;이전에 가지고 있지 않은 경우 에도 필요 합니다.
yellavon

1
참고 : list1.Except (list2)는 list2.Except (list1)과 동일한 결과를 제공하지 않습니다. 마지막은 나를 위해 일했다.
radbyx

2
Except실제로 결과 목록을 구별 하는 설정 조작을 수행하므로 사용시주의 하십시오. 을 사용하지 않고이 동작을 기대 List하지 않았습니다 HashSet. 관련.
logan

4
이것이 어떻게 정답입니까? 물론 이것이 당신에게 당신의 맥락에서 원하는 것을 줄 수도 있지만, "다른 목록에서 항목을 제거하십시오"는 분명히 설정된 차이 연산과 같지 않으며, 이것을 정답으로 받아 들여 사람들에게 잘못 알려주지 않아야합니다 !!!!
user1935724

37

List<T>클래스를 사용하면 Remove함수 를 사용하여 인덱스가 아닌 값으로 항목을 제거 할 수 있으므로 인덱스가 필요하지 않습니다 .

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

3
+1이지만 IMO는 list2.Remove(item);문장 주위에 괄호를 사용해야 합니다.
ANeves

2
@ sr pt : 나는 항상 다른 줄에 나타나는 문에 괄호를 사용하지만 흐름 제어 문과 같은 줄에 배치 할 수있는 단일 문 블록에는 사용하지 않습니다.
Adam Robinson

4
@uriz : 우아한 것의 자격을 무시하고, 이것은 실제로 질문에서 말하는 것을 수행하는 유일한 대답입니다 (메인 목록의 항목 제거). 다른 답변은 목록을 생성하는데 , 이는 교체 목록을 얻는 대신 목록을 수정하려는 다른 호출자로부터 목록을 전달하는 경우 바람직하지 않을 수 있습니다.
Adam Robinson

5
@uriz @AdamRobinson 우리가 우아한 솔루션을 논의한 이래 ...list1.ForEach(c => list2.Remove(c));
David Sherret

1
"우아한"은 "개발자가이 코드를 유지 관리하는 것이 간단하고 이해하기 쉽다는 것을 알게 될 것입니다"를 의미해야합니다. 이것이 이것이 가장 좋은 대답입니다.
세스

22

LINQ 확장 방법을 사용하는 것이 좋습니다 . 한 줄의 코드로 쉽게 수행 할 수 있습니다.

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

이것은 물론 list2에서 제거하는 list1의 객체가 동일한 인스턴스라고 가정합니다.


2
중복도 제거합니다.
July

17

필자의 경우 외래 키와 같은 공통 식별자가있는 두 개의 다른 목록이있었습니다. "nzrytmn"에 의해 인용 된 두 번째 해결책 :

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


7

솔루션 1 : 다음과 같이 할 수 있습니다 :

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

그러나 경우에 따라이 솔루션이 작동하지 않을 수 있습니다. 그것이 작동하지 않으면 내 두 번째 솔루션을 사용할 수 있습니다.

해결책 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. 첫 번째 항목을 제거한 후 예외가 발생합니다. 또한 일반적 으로 크기가 더 작기 때문에 목록을 탐색하여 제거 하는 것이 좋습니다 . 또한이 방법으로 더 많은 목록 순회를 강요합니다.
Adam Robinson
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.