두 목록의 차이점


118

CustomsObjects로 채워진 두 개의 일반 목록이 있습니다.

세 번째 목록에서 두 목록 (두 번째 목록의 항목없이 첫 번째 목록에있는 항목)의 차이점을 검색해야합니다.

사용 .Except()하는 것이 좋은 생각이라고 생각했지만 사용 방법을 모르겠습니다 .. 도움말!

c# 

답변:


237

사용하는 Except것이 바로 올바른 방법입니다. 만약 당신의 유형 대체 Equals하고 GetHashCode, 또는 당신은 단지 참조 유형 평등에 관심이있는 (즉, 두 개의 참조이다 그들이 동일한 객체를 참조하는 경우에만 "동일"), 당신은 그냥 사용할 수 있습니다 :

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

예를 들어 ID로 동일성에 대한 사용자 정의 아이디어를 표현해야하는 경우 IEqualityComparer<T>. 예를 들면 :

public class IdComparer : IEqualityComparer<CustomObject>
{
    public int GetHashCode(CustomObject co)
    {
        if (co == null)
        {
            return 0;
        }
        return co.Id.GetHashCode();
    }

    public bool Equals(CustomObject x1, CustomObject x2)
    {
        if (object.ReferenceEquals(x1, x2))
        {
            return true;
        }
        if (object.ReferenceEquals(x1, null) ||
            object.ReferenceEquals(x2, null))
        {
            return false;
        }
        return x1.Id == x2.Id;
    }
}

그런 다음 다음을 사용하십시오.

var list3 = list1.Except(list2, new IdComparer()).ToList();

이렇게하면 모든 중복 요소가 제거됩니다. 중복을 보존해야하는 경우 list2다음과 같이 집합을 만들고 사용하는 것이 가장 쉬울 것입니다 .

var list3 = list1.Where(x => !set2.Contains(x)).ToList();

18
제쳐두고, 나는 그것이 Set 연산 이라는 것을 추가 할 것 Except입니다. 그러면 결과 목록은 고유 한 값을 가질 것입니다. 예 : returns{'A','A','B','C'}.Except({'B','C'}){'A'}
digEmAll

4
나는 이것을 가지고있다 : { 'A', 'A', 'B', 'C'}. Except ({ 'B', 'C'})는 작동하는 { 'A'}를 반환하지만 ... 그러나 { 'B' , 'C'}. Except ({ 'A', 'B', 'C'})는 { 'A'}를 반환하지 않습니다
MrLister

2
두 세트의 세트 차이는 두 번째 세트 (MS 인용)에 나타나지 않는 첫 번째 세트의 구성원으로 정의됩니다. 따라서 {B, C} .Except ({A, B, C})는 B와 C가 모두 두 번째 세트에 있으므로 아무것도 반환하지 않아야합니다. 버그가 아니라 함수의 수학적 정의와 관련이 있습니다.
Steve Hibbert

그래서 @JonSkeet 2 개의 속성을 기준으로 두 목록을 비교하고 싶다면이 방식으로 비교자를 작성하고 같지 않은 항목을 얻을 수 있다고 가정 해 보겠습니다.
Ehsan Sajjad

1
@NetMage : OP는 "두 번째 항목없이 첫 번째 항목에있는 항목"을 원한다고 말했습니다. 이는 저에게 정해진 차이처럼 들립니다. 첫 번째 목록에 {5, 5, 5, 5, 1}이 포함되고 두 번째 목록에 {5}가 포함 된 경우 첫 번째 목록에는 1 개만 있고 두 번째 목록에는 없습니다.
존 소총

73

다음과 같이 할 수 있습니다.

var result = customlist.Where(p => !otherlist.Any(l => p.someproperty == l.someproperty));

그것은 나에게 하나의 foreach 루프를 저장했습니다.
alice7

12
"l.someproperty"중 하나가 "p.someproperty"여야하지 않습니까?
Manos Dilaverakis

6
customlist.Where (p => otherlist.Any (l => p.someproperty! = l.someproperty));
Dhanuka777

@ Dhanuka777 틀 렸습니다. 는 Any을해야 All당신이 그런 식으로 작업을 수행하려는 경우. 두 번째 목록에 첫 번째 목록의 항목이있을 수 있지만 첫 번째 목록이 확인되지 않은 경우 즉시 p.someproperty != l.someproperty. 이로 인해 두 목록에 모두있는 항목이 반환됩니다. 이것을 찬성 한 6 명에게 수치심.
Murphybro2

26

강조하는 것이 중요하다고 생각합니다. Except 메서드 를 사용 하면 두 번째 항목 만 제외하고 첫 번째 항목에있는 항목 만 반환됩니다. 첫 번째에 나타나지 않는 두 번째 요소는 반환하지 않습니다.

var list1 = new List<int> { 1, 2, 3, 4, 5};
var list2 = new List<int> { 3, 4, 5, 6, 7 };

var list3 = list1.Except(list2).ToList(); //list3 contains only 1, 2

그러나 두 목록의 실제 차이를 원한다면 :

두 번째 항목이없는 첫 번째 항목과 첫 번째 항목이없는 두 번째 항목입니다.

Except를 두 번 사용해야합니다.

var list1 = new List<int> { 1, 2, 3, 4, 5};
var list2 = new List<int> { 3, 4, 5, 6, 7 };

var list3 = list1.Except(list2); //list3 contains only 1, 2
var list4 = list2.Except(list1); //list4 contains only 6, 7
var resultList = list3.Concat(list4).ToList(); //resultList contains 1, 2, 6, 7

또는 HashSet의 SymmetricExceptWith 메소드를 사용할 수 있습니다 . 그러나 다음과 같은 세트를 변경합니다.

var list1 = new List<int> { 1, 2, 3, 4, 5};
var list2 = new List<int> { 3, 4, 5, 6, 7 };

var list1Set = list1.ToHashSet(); //.net framework 4.7.2 and .net core 2.0 and above otherwise new HashSet(list1)
list1Set.SymmetricExceptWith(list2);
var resultList = list1Set.ToList(); //resultList contains 1, 2, 6, 7

도움이 되네요. OP는 그들이 완전한 차이를 원하지 않는다는 것을 분명히했다 : "나는 두 목록 (두 번째 목록에 있는 항목없이 첫 번째 목록에있는 항목) 간의 차이를 검색해야합니다 ."
rsenna

10
var third = first.Except(second);

(당신은 또한 호출 할 수 있습니다 ToList()Except()당신이 게으른 컬렉션을 참조하는 마음에 들지 않으면.)

Except()값이 같은베이스 데이터 유형이다 비교되는 경우에있어서, 기본 비교를 사용하여 값을 비교 int, string, decimal

그렇지 않으면 객체 주소로 비교가 이루어집니다. 이는 아마도 원하는 것이 아닐 것입니다 ...이 경우 사용자 지정 개체를 구현 IComparable(또는 사용자 지정을 구현 IEqualityComparer하고 Except()메서드에 전달 )합니다.


3
var list3 = list1.Where(x => !list2.Any(z => z.Id == x.Id)).ToList();

참고 : list3두 목록에없는 항목 또는 개체가 포함됩니다. 참고 : ToList()아닙니다toList()


1

Except 확장 메서드는 두 개의 IEumerable에서 작동하기 때문에 O (n ^ 2) 작업이 될 것 같습니다. 성능이 문제인 경우 (목록이 큰 경우) list1에서 HashSet을 만들고 HashSet의 ExceptWith 메서드를 사용하는 것이 좋습니다.


9
Enumerable.Except내부적으로 사용 HashSet하거나 유사한 것. 순진한 O (n ^ 2) 알고리즘을 사용하지 않습니다.
Jim Mischel 2011

@Jim Mischel : 맞습니다, Enumerable.Except는 내부 Set 데이터 구조를 사용하고 두 IEnumerables의 항목을 Set에 추가합니다. 문서가 그것에 대해 말하길 바랍니다.
foson

1

내 해결책은 다음과 같습니다.

    List<String> list1 = new List<String>();

    List<String> list2 = new List<String>();

    List<String> exceptValue = new List<String>();

foreach(String L1 in List1) 
{
    if(!List2.Contains(L1)
    {
         exceptValue.Add(L1);
    }
}
foreach(String L2 in List2) 
{
    if(!List1.Contains(L2)
    {
         exceptValue.Add(L2);
    }
}

-1

조금 늦었지만 여기에 나를 위해 일하는 해결책이 있습니다.

 var myBaseProperty = (typeof(BaseClass)).GetProperties();//get base code properties
                    var allProperty = entity.GetProperties()[0].DeclaringType.GetProperties();//get derived class property plus base code as it is derived from it
                    var declaredClassProperties = allProperty.Where(x => !myBaseProperty.Any(l => l.Name == x.Name)).ToList();//get the difference

위의 언급 코드에서 기본 클래스와 파생 클래스 목록 간의 속성 차이를 얻고 있습니다.


-1
var resultList = checklist.Where(p => myList.All(l => p.value != l.value)).ToList();

참고 : 결과 목록은 체크리스트에는 있지만 myList에는없는 항목입니다
Teezy7

-2
List<ObjectC> _list_DF_BW_ANB = new List<ObjectC>();    
List<ObjectA> _listA = new List<ObjectA>();
List<ObjectB> _listB = new List<ObjectB>();

foreach (var itemB in _listB )
{     
    var flat = 0;
    foreach(var itemA in _listA )
    {
        if(itemA.ProductId==itemB.ProductId)
        {
            flat = 1;
            break;
        }
    }
    if (flat == 0)
    {
        _list_DF_BW_ANB.Add(itemB);
    }
}

6 허용 대답 후 년 새로운 가치 아무것도 추가하지
미치 밀

-3

두 목록 모두 IEnumerable 인터페이스를 구현하는 경우 LINQ를 사용하여이를 수행 할 수 있습니다.

list3 = list1.where(i => !list2.contains(i));

6
목록에 각각 백만 개의 항목이 포함되어 있으면 오랜 시간이 걸릴 것입니다. IEnumerable.Except대신 사용하십시오 .
Jim Mischel 2011

3
네. 나는 약 450 개의 품목을 가지고 있으며 아직 기다리고 있습니다. 이것을 사용하여 조심하십시오.
Marnee KG7SIO

-3
        List<int> list1 = new List<int>();
        List<int> list2 = new List<int>();
        List<int> listDifference = new List<int>();

        foreach (var item1 in list1)
        {
            foreach (var item2 in list2)
            {
                if (item1 != item2)
                    listDifference.Add(item1);
            }
        }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.