外部アプリから返される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 (?,?,?)
クエリを使用します。
次のように使用する 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オブジェクトを人から選択します。
ListクラスでFindAllメソッドを使用するだけです。すなわち:
List<Person> filteredResults =
people.FindAll(p => return !exclusions.Contains(p));
構文がオブジェクトに正確に一致するかどうかはわかりませんが、これでどこに行くのかを見ることができると思います。
この人たちに感謝します。
これをなんとか1行にまとめることができました。
var results = from p in People
where !(from e in exclusions
select e.CompositeKey).Contains(p.CompositeKey)
select p;
みんなありがとう。
「Except」拡張メソッドを使用できます( http://msdn.Microsoft.com/en-us/library/bb337804.aspx を参照)
あなたのコードで
var difference = people.Except(exclusions);
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
それに応じてリストのタイプとラムダを調整すると、何でもフィルタリングできます。
純粋な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
}
}
私はこのようなことをしますが、もっと簡単な方法があると思います。私は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);
}
}
}
以下のこの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
動作するかどうか教えてください!