421


82

LINQを使用して、1つのList <>にあるアイテムを取得しますが、別のList <>にはありません

これを行うための簡単なLINQクエリがあると思いますが、どのようにすればよいかわかりません。 以下のコードスニペットをご覧ください。

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

        List peopleList2 = new List();
        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クエリを実行して、 peopleList1`にない peopleList2`のすべてのユーザーを取得したいのですが、この例では2人のユーザー(ID = 4&ID = 5)が必要です。

10 Answer


739


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


318


Peopleの平等をオーバーライドする場合、次も使用できます。

peopleList2.Except(peopleList1)

Except`は2番目のリストをハッシュテーブルに入れることができるため、 Where(…​ Any) バリアントよりも大幅に高速になります。 `Where(…​ Any)`のランタイムは `O(peopleList1.Count * peopleList2.Count)`ですが、 `HashSet`に基づくバリアント(ほぼ)のランタイムは O(peopleList1.Count + peopleList2.Count)です`。

`Except`は重複を暗黙的に削除します。 それはあなたのケースに影響を与えるべきではありませんが、同様のケースでは問題になるかもしれません。

または、高速なコードが必要であるが、等式をオーバーライドしたくない場合:

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

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


53


または、否定なしでそれが必要な場合:

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

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

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


28


これまでのソリューションはすべて流syntaxな構文を使用していたため、興味のある方のために、クエリ式構文のソリューションを以下に示します。

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

これは、リストにとって最適ではない可能性が高いと考えられていたとしても、一部の人にとって興味深い回答とは十分に異なると思います。 インデックス付きIDを持つテーブルの場合、これは間違いなく進むべき方法です。


12


パーティーに少し遅れましたが、Linq to SQLと互換性のある優れたソリューションは次のとおりです。

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

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

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

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


7


Klausの答えは素晴らしかったが、ReSharperは「LINQ式を単純化する」ように求めてくる。

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


6


このEnumerable Extensionを使用すると、除外するアイテムのリストと、比較の実行に使用するキーを見つけるために使用する関数を定義できます。

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

このように使うことができます

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


0


以下は、求職者がまだ持っていないITスキルを習得する実例です。

//Get a list of skills from the Skill table
IEnumerable skillenum = skillrepository.Skill;
//Get a list of skills the candidate has
IEnumerable 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 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


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

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

次に、「compare」estamentを使用して、選択とは異なるIDを選択します

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

明らかにx.key!= "TEST"を使用できますが、これは単なる例です


0


汎用FuncEqualityComparerを作成すると、どこでも使用できます。

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

public class FuncEqualityComparer : IEqualityComparer
{
    private readonly Func comparer;
    private readonly Func hash;

    public FuncEqualityComparer(Func 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);
}