c# linq distinct




한 List<>에서 다른 List<>에없는 항목을 가져 오려면 LINQ를 사용하십시오. (6)

Enumerable Extension을 사용하면 제외 할 항목 목록과 비교를 수행하는 데 사용할 키를 찾는 데 사용할 함수를 정의 할 수 있습니다.

public static class EnumerableExtensions
{
    public static IEnumerable<TSource> Exclude<TSource, TKey>(this IEnumerable<TSource> source,
    IEnumerable<TSource> exclude, Func<TSource, TKey> keySelector)
    {
       var excludedSet = new HashSet<TKey>(exclude.Select(keySelector));
       return source.Where(item => !excludedSet.Contains(keySelector(item)));
    }
}

이런 식으로 사용할 수 있습니다.

list1.Exclude(list2, i => i.ID);

이 작업을 수행하기위한 간단한 LINQ 쿼리가 있다고 가정하고, 정확히 어떻게 확신 할 수는 없습니다. 아래의 코드 스 니펫을 참조하십시오.

class Program
{
    static void Main(string[] args)
    {
        List<Person> peopleList1 = new List<Person>();
        peopleList1.Add(new Person() { ID = 1 });
        peopleList1.Add(new Person() { ID = 2 });
        peopleList1.Add(new Person() { ID = 3 });

        List<Person> peopleList2 = new List<Person>();
        peopleList2.Add(new Person() { ID = 1 });
        peopleList2.Add(new Person() { ID = 2 });
        peopleList2.Add(new Person() { ID = 3 });
        peopleList2.Add(new Person() { ID = 4 });
        peopleList2.Add(new Person() { ID = 5 });
    }
}

class Person
{
    public int ID { get; set; }
}

peopleList2 에없는 peopleList2 모든 사람들에게 LINQ 쿼리를 수행하여이 예제에서 두 사람 (ID = 4 및 ID = 5)을 제공해야합니다.


Klaus의 답변은 훌륭했지만 ReSharper는 "LINQ 표현을 단순화"하도록 요청할 것입니다.

var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));


당신이 사람의 평등을 무시한다면 당신은 또한 다음을 사용할 수 있습니다 :

peopleList2.Except(peopleList1)

두 번째 목록을 해시 테이블에 넣을 수 있으므로 Where(...Any) 변형보다 훨씬 빠르게해야합니다. HashSet<T> (거의)을 기반으로하는 변형은 O(peopleList1.Count + peopleList2.Count) 의 런타임을 갖는 반면, Where(...Any)O(peopleList1.Count * peopleList2.Count) 의 런타임 O(peopleList1.Count + peopleList2.Count) .

Except 암시 적으로 중복을 제거합니다. 귀하의 사례에 영향을 미치지 않아야하지만 비슷한 경우에는 문제가 될 수 있습니다.

또는 빠른 코드를 원하지만 동일성을 무시하고 싶지 않은 경우 :

var excludedIDs = new HashSet<int>(peopleList1.Select(p => p.ID));
var result = peopleList2.Where(p => !excludedIDs.Contains(p.ID));

이 변형은 중복을 제거하지 않습니다.


또는 부정하지 않고 원할 경우 :

var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));

기본적으로 peopleList1의 모든 ID가 peoplesList2의 id와 다른 peopleList2를 모두 얻습니다.

수락 된 대답에서 조금 다른 접근법 :)


지금까지의 모든 솔루션은 유창한 구문을 사용 했으므로 여기에는 쿼리 식 구문의 해결책이 있습니다.

var peopleDifference = 
  from person2 in peopleList2
  where !(
      from person1 in peopleList1 
      select person1.ID
    ).Contains(person2.ID)
  select person2;

나는 그것이 관심사가되기 위해 주어진 답변과 충분히 다르다고 생각한다. 심지어 목록에 대해 가장 차선책이라고 생각할지라도. 인덱싱 된 ID가있는 테이블의 경우이 방법이 반드시 필요합니다.


var result = peopleList2.Where(p => !peopleList1.Any(p2 => p2.ID == p.ID));




.net-3.5