web-dev-qa-db-ja.com

LINQを使用して、あるリスト<>のアイテムを取得しますが、それは別のリスト<>にはありません。

私はこれを行うための単純な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に含まれていないpeopleList1に含まれているすべてのユーザーに2人のユーザーが割り当てられているはずです(ID = 4&ID = 5)。

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

人の平等を無効にする場合は、次のものも使用できます。

peopleList2.Except(peopleList1)

Exceptは、2番目のリストをハッシュテーブルに入れることができるので、Where(...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));

このバリアントは重複を削除しません。

326
CodesInChaos

あなたが否定せずにそれをしたい場合は:

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

基本的に、peopleList1のすべてのIDがpeoplesList2のidとは異なる、peopleList2からすべてを取得するということです。

受け入れられた答えとは少し異なるアプローチ:)

57
user1271080

これまでのすべての解決策は流暢な構文を使用していたので、興味のある人のために、これはクエリ式の構文の解決策です。

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

私はそれがリストにとっては最善ではないと考えていたとしても、それがある人にとって興味を引くために与えられた答えとは十分に異なると思います。インデックス付きのIDを持つテーブルの場合、これは間違いなく有効な方法です。

28

パーティーには少し時間がかかりますが、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 に敬意を表します

13
Richard Ockerby

Klausの答えは素晴らしかった、しかしReSharperはあなたに「単純化LINQ表現」を尋ねるでしょう:

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

8
Brian T

この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);
7
Bertrand

一般的な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);
}
0
Wouter

これは、求職者がまだ持っていない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);
0
Brian Quinn

最初に、コレクションのwhere where条件からIDを抽出します。

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

第二に、選択と異なるIDを選択するために "compare"要素を使う

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

明らかにあなたはx.key!= "TEST"を使うことができますが、それはほんの一例です

0
Ángel Ibáñez