development

LINQ를 사용하여 하나의 List <>에서 다른 List <>에없는 항목을 가져옵니다.

big-blog 2020. 2. 14. 23:45
반응형

LINQ를 사용하여 하나의 List <>에서 다른 List <>에없는 항목을 가져옵니다.


이 작업을 수행하는 간단한 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; }
}

LINQ 쿼리를 수행 하여이 예제에 peopleList2없는 모든 사람들 peopleList1에게 나에게 두 사람을 주어야합니다 (ID = 4 & ID = 5)


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

People의 평등을 무시하면 다음을 사용할 수도 있습니다.

peopleList2.Except(peopleList1)

ExceptWhere(...Any)두 번째 목록을 해시 테이블에 넣을 수 있으므로 변형 보다 훨씬 빠릅니다 . Where(...Any)의 런타임이있는 O(peopleList1.Count * peopleList2.Count)반면 HashSet<T>(거의) 기반 변형 은의 런타임이 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가있는 테이블의 경우 이것이 확실합니다.


파티에 늦었지만 Linq to SQL 호환 가능한 좋은 솔루션은 다음과 같습니다.

List<string> list1 = new List<string>() { "1", "2", "3" };
List<string> list2 = new List<string>() { "2", "4" };

List<string> inList1ButNotList2 = (from o in list1
                                   join p in list2 on o equals p into t
                                   from od in t.DefaultIfEmpty()
                                   where od == null
                                   select o).ToList<string>();

List<string> inList2ButNotList1 = (from o in list2
                                   join p in list1 on o equals p into t
                                   from od in t.DefaultIfEmpty()
                                   where od == null
                                   select o).ToList<string>();

List<string> inBoth = (from o in list1
                       join p in list2 on o equals p into t
                       from od in t.DefaultIfEmpty()
                       where od != null
                       select od).ToList<string>();

http://www.dotnet-tricks.com/Tutorial/linq/UXPF181012-SQL-Joins-with-C에 대한 조언


클라우스의 대답은 훌륭했지만 ReSharper는 "LINQ 표현 단순화"를 요청합니다.

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


이 열거 가능 확장 기능을 사용하면 제외 할 항목 목록과 비교를 수행하는 데 사용할 키를 찾는 데 사용할 함수를 정의 할 수 있습니다.

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

다음은 구직자에게없는 IT 기술을 익히는 실무 예제입니다.

//Get a list of skills from the Skill table
IEnumerable<Skill> skillenum = skillrepository.Skill;
//Get a list of skills the candidate has                   
IEnumerable<CandSkill> candskillenum = candskillrepository.CandSkill
       .Where(p => p.Candidate_ID == Candidate_ID);             
//Using the enum lists with LINQ filter out the skills not in the candidate skill list
IEnumerable<Skill> skillenumresult = skillenum.Where(p => !candskillenum.Any(p2 => p2.Skill_ID == p.Skill_ID));
//Assign the selectable list to a viewBag
ViewBag.SelSkills = new SelectList(skillenumresult, "Skill_ID", "Skill_Name", 1);

먼저 조건이있는 컬렉션에서 ID를 추출합니다.

List<int> indexes_Yes = this.Contenido.Where(x => x.key == 'TEST').Select(x => x.Id).ToList();

둘째, "비교"estament를 사용하여 선택과 다른 ID를 선택하십시오.

List<int> indexes_No = this.Contenido.Where(x => !indexes_Yes.Contains(x.Id)).Select(x => x.Id).ToList();

분명히 x.key! = "TEST"를 사용할 수 있지만 단지 예일뿐입니다


일반 FuncEqualityComparer를 작성하면 어디서나 사용할 수 있습니다.

peopleList2.Except(peopleList1, new FuncEqualityComparer<Person>((p, q) => p.ID == q.ID));

public class FuncEqualityComparer<T> : IEqualityComparer<T>
{
    private readonly Func<T, T, bool> comparer;
    private readonly Func<T, int> hash;

    public FuncEqualityComparer(Func<T, T, bool> comparer)
    {
        this.comparer = comparer;
        if (typeof(T).GetMethod(nameof(object.GetHashCode)).DeclaringType == typeof(object))
            hash = (_) => 0;
        else
            hash = t => t.GetHashCode(); 
    }

    public bool Equals(T x, T y) => comparer(x, y);
    public int GetHashCode(T obj) => hash(obj);
}

참고 URL : https://stackoverflow.com/questions/3944803/use-linq-to-get-items-in-one-list-that-are-not-in-another-list



반응형