web-dev-qa-db-ja.com

linq結合に「等しくない」がありますか

以下のLINQクエリを実行しようとしていますが、filteredEmployeesにはgroupAからgroupBを引いたすべての従業員がいるように、等しいではなく「等しくない」が必要です。

List<Employee> groupA = getEmployeeA();
List<Employee> groupB = getEmployeeB();        

var filteredEmployees = from a in groupA 
                        join b in groupB on a.Name equals b.Name
                        select a;
29
Robert

そのために参加する必要はありません。

var filteredEmployees = groupA.Except(groupB);

これは一意の従業員のシーケンスであることに注意してください。したがって、groupAに重複がある場合、filteredEmployeesには一度しか表示されません。もちろん、合理的な等値比較器があることも前提としています1。名前を明確にする必要がある場合は、 ExceptBy from MoreLINQ を使用できます。

var filteredEmployees = groupA.ExceptBy(groupB, employee => employee.Name);

または、サードパーティのライブラリに入らずに:

var groupBNames = new HashSet<string>(groupB.Select(x => x.Name));
var filteredEmployees = groupA.Where(x => !groupBNames.Contains(x.Name));

1 コメントで指摘したように、IEqualityComparer<T>Exceptの引数として渡すことができます。 MiscUtilProjectionEqualityComparerクラスがあり、必要な種類の比較器を簡単に作成できます。

// I can't remember the exact method name, but it's like this :)
var comparer = ProjectionEqualityComparer<Employee>.Create(x => x.Name);
var filteredEmployees = groupA.Except(groupB, comparer);
53
Jon Skeet

いいえ、「等しくない」演算子は、アイテムが同じであるものを除く、groupAとgroupBのすべての組み合わせを取得します。

Exceptメソッドを使用すると、必要なものが得られます。

var filteredEmployees = groupA.Except(groupB);
4
Guffa

Entity Framework 6では、次を使用してより良い結果が得られました

var filteredEmployees = groupA.Where(a => !groupB.Select(b => b.Name).Contains(a.Name));
3
mcandal

サーバーコストを削減するためのこのコードの使用:

コードは他のコードと比較して非常に高速に動作します

        var noExistList = (from n in groupA 
                                join o in groupA  on n.Id equals o.Id into p
                                where p.Count() == 0
                                select n).ToList();

注:groupAは追加用の新しいリストです。

0
FatalMan