J'ai une liste de personnes renvoyées par une application externe et je crée une liste d'exclusion dans mon application locale pour me permettre de supprimer manuellement les personnes de la liste.
J'ai créé une clé composite qui est commune aux deux et je souhaite trouver un moyen efficace de supprimer des personnes de ma liste à l'aide de ma liste.
par exemple
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
Je pensais que LINQ était le moyen idéal de le faire, mais après avoir essayé des jointures, des méthodes d'extension, utilisé des rendements, etc., j'ai toujours des problèmes.
S'il s'agissait de SQL, j'utiliserais une requête not in (?,?,?)
.
Jetez un coup d’œil à la méthode Sauf que vous utilisez comme ceci:
var resultingList =
listOfOriginalItems.Except(listOfItemsToLeaveOut, equalityComparer)
Vous voudrez utiliser la surcharge à laquelle j'ai lié, ce qui vous permet de spécifier un IEqualityComparer personnalisé. De cette façon, vous pouvez spécifier la correspondance des éléments en fonction de votre clé composite. (Cependant, si vous avez déjà remplacé Equals, vous n’aurez pas besoin de IEqualityComparer.)
Edit: Puisqu'il semble que vous utilisez deux types de classes différents, voici une autre méthode plus simple. En supposant un List<Person>
appelé persons
et un List<Exclusion>
appelé exclusions
:
var exclusionKeys =
exclusions.Select(x => x.compositeKey);
var resultingPersons =
persons.Where(x => !exclusionKeys.Contains(x.compositeKey));
En d'autres termes: sélectionnez dans les exclusions uniquement les clés, puis sélectionnez parmi les personnes tous les objets Personne qui n'ont pas n'ont aucune de ces clés.
Je voudrais simplement utiliser la méthode FindAll sur la classe List. c'est à dire.:
List<Person> filteredResults =
people.FindAll(p => return !exclusions.Contains(p));
Pas sûr que la syntaxe corresponde exactement à vos objets, mais je pense que vous pouvez voir où je veux en venir.
Merci beaucoup pour ce gars.
J'ai réussi à réduire cela à une ligne:
var results = from p in People
where !(from e in exclusions
select e.CompositeKey).Contains(p.CompositeKey)
select p;
Merci encore à tous.
Vous pouvez utiliser la méthode d'extension "Except" (voir http://msdn.Microsoft.com/en-us/library/bb337804.aspx ).
Dans votre code
var difference = people.Except(exclusions);
Je ne savais pas comment faire cela dans MS LINQ pur, alors j'ai écrit ma propre méthode d'extension pour le faire:
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
}
}
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
Adaptez les types de liste et les lambdas en conséquence, et vous pouvez tout filtrer.
Je voudrais faire quelque chose comme ça mais je parie qu'il existe un moyen plus simple. Je pense que le sql de linq à sql pourrait utiliser un choix de personne où PAS EXIST (sélectionnez dans votre liste d'exclusion)
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);
}
}
}
Ce LINQ ci-dessous générera le code SQL pour une jointure externe gauche, puis prendra tous les résultats qui ne correspondent à aucune correspondance dans votre liste d'exclusion.
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
laissez-moi savoir si cela fonctionne!