web-dev-qa-db-fra.com

Filtrage des listes à l'aide de LINQ

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 (?,?,?).

15
keeno

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.

30
Ryan Lundy

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.

4
BFree

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.

2
keeno

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);
2
Fabrizio C.

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
    }
}
1
Jason Jackson
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.

https://dotnetfiddle.net/6bMCvN

0
Wes

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);
       }
    }
 }
0
Hath

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!

0
Noah