web-dev-qa-db-ja.com

LINQを使用したリストのフィルタリング

外部アプリから返されるPeopleのリストがあり、ローカルアプリで除外リストを作成して、リストから人を手動で削除するオプションを提供しています。

私は両方に共通の複合キーを作成しており、リストを使用してリストから人々を削除する効率的な方法を見つけたい

例えば

_class Person
{
    prop string compositeKey { get; set; }
}

class Exclusions
{
    prop string compositeKey { get; set; }
}

List<Person> people = GetFromDB;

List<Exclusions> exclusions = GetFromOtherDB;

List<Person> filteredResults = People - exclustions using the composite key as a comparer
_

私はLINQがこれを行う理想的な方法だと思っていましたが、結合、拡張メソッド、yieldの使用などを試みた後、私はまだ問題を抱えています。

これがSQLの場合、not in (?,?,?)クエリを使用します。

20
keeno

次のように使用する Except メソッドを見てください。

var resultingList = 
    listOfOriginalItems.Except(listOfItemsToLeaveOut, equalityComparer)

リンクしたオーバーロードを使用すると、カスタムIEqualityComparerを指定できます。このようにして、複合キーに基づいてアイテムの一致方法を指定できます。 (ただし、既にEqualsをオーバーライドしている場合、IEqualityComparerは必要ありません。)

Edit:2つの異なるタイプのクラスを使用しているように見えるので、より簡単な別の方法を次に示します。 List<Person>personsおよびList<Exclusion>exclusionsと呼ばれます:

var exclusionKeys = 
        exclusions.Select(x => x.compositeKey);
var resultingPersons = 
        persons.Where(x => !exclusionKeys.Contains(x.compositeKey));

言い換えると、除外からキーのみを選択し、ないキーを持たないすべてのPersonオブジェクトを人から選択します。

32
Ryan Lundy

ListクラスでFindAllメソッドを使用するだけです。すなわち:

List<Person> filteredResults = 
    people.FindAll(p => return !exclusions.Contains(p));

構文がオブジェクトに正確に一致するかどうかはわかりませんが、これでどこに行くのかを見ることができると思います。

4
BFree

この人たちに感謝します。

これをなんとか1行にまとめることができました。

  var results = from p in People 
                where !(from e in exclusions 
                        select e.CompositeKey).Contains(p.CompositeKey) 
                select p;

みんなありがとう。

3
keeno

「Except」拡張メソッドを使用できます( http://msdn.Microsoft.com/en-us/library/bb337804.aspx を参照)

あなたのコードで

var difference = people.Except(exclusions);
2
Fabrizio C.
var thisList = new List<string>{ "a", "b", "c" };
var otherList = new List<string> {"a", "b"};

var theOnesThatDontMatch = thisList
        .Where(item=> otherList.All(otherItem=> item != otherItem))
        .ToList();

var theOnesThatDoMatch = thisList
        .Where(item=> otherList.Any(otherItem=> item == otherItem))
        .ToList();

Console.WriteLine("don't match: {0}", string.Join(",", theOnesThatDontMatch));
Console.WriteLine("do match: {0}", string.Join(",", theOnesThatDoMatch));

//Output:
//don't match: c
//do match: a,b

それに応じてリストのタイプとラムダを調整すると、何でもフィルタリングできます。

https://dotnetfiddle.net/6bMCvN

1
Wes

純粋なMS LINQでこれを行う方法がわからなかったため、それを行う独自の拡張メソッドを作成しました。

public static bool In<T>(this T objToCheck, params T[] values)
{
    if (values == null || values.Length == 0) 
    {
        return false; //early out
    }
    else
    {
        foreach (T t in values)
        {
            if (t.Equals(objToCheck))
                return true;   //RETURN found!
        }

        return false; //nothing found
    }
}
1
Jason Jackson

私はこのようなことをしますが、もっと簡単な方法があると思います。私はlinqtosqlのSQLが存在しない人からの選択を使用すると思います(除外リストから選択してください)

static class Program
{
    public class Person
    {
        public string Key { get; set; }
        public Person(string key)
        {
           Key = key;
        }
    }
    public class NotPerson
    {
        public string Key { get; set; }
        public NotPerson(string key)
        {
           Key = key;
        }
    }
    static void Main()
    {

       List<Person> persons = new List<Person>()
       { 
           new Person ("1"),
           new Person ("2"),
           new Person ("3"),
           new Person ("4")
       };

       List<NotPerson> notpersons = new List<NotPerson>()
       { 
           new NotPerson ("3"),
           new NotPerson ("4")
       };

       var filteredResults = from n in persons
                             where !notpersons.Any(y => n.Key == y.Key)
                             select n;

       foreach (var item in filteredResults)
       {
          Console.WriteLine(item.Key);
       }
    }
 }
0
Hath

以下のこのLINQは、左外部結合のSQLを生成し、除外リストに一致するものが見つからないすべての結果を取得します。

List<Person> filteredResults =from p in people
        join e in exclusions on p.compositeKey equals e.compositeKey into temp
        from t in temp.DefaultIfEmpty()
        where t.compositeKey == null
        select p

動作するかどうか教えてください!

0
Noah