webentwicklung-frage-antwort-db.com.de

Filtern von Listen mit LINQ

Ich habe eine Liste mit Personen, die von einer externen App zurückgegeben werden, und ich erstelle eine Ausschlussliste in meiner lokalen App, um mir die Möglichkeit zu geben, Personen manuell aus der Liste zu entfernen. 

Ich habe einen zusammengesetzten Schlüssel, den ich erstellt habe, der beiden gemeinsam ist, und ich möchte einen effizienten Weg finden, Personen mithilfe meiner Liste von meiner Liste zu entfernen 

z.B 

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

Ich dachte, LINQ wäre der ideale Weg, aber nachdem ich Joins, Erweiterungsmethoden, Verwendung von Erträgen usw. ausprobiert hatte, habe ich immer noch Probleme. 

Wenn dies SQL wäre, würde ich eine not in (?,?,?)-Abfrage verwenden.

15
keeno

Schauen Sie sich die Methode Except an, die Sie wie folgt verwenden:

var resultingList = 
    listOfOriginalItems.Except(listOfItemsToLeaveOut, equalityComparer)

Sie möchten die Überladung verwenden, mit der ich verlinkt habe, wodurch Sie einen benutzerdefinierten IEqualityComparer angeben können. Auf diese Weise können Sie basierend auf Ihrem zusammengesetzten Schlüssel festlegen, wie Elemente übereinstimmen. (Wenn Sie Equals jedoch bereits überschrieben haben, sollten Sie den IEqualityComparer nicht benötigen.)

Edit: Da es so aussieht, als würden Sie zwei verschiedene Arten von Klassen verwenden, gibt es einen anderen Weg, der möglicherweise einfacher ist. Angenommen, ein List<Person> namens persons und ein List<Exclusion> genannt exclusions:

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

Mit anderen Worten: Wählen Sie aus den Ausschlüssen nur die Schlüssel aus und wählen Sie dann alle Personenobjekte aus, die nicht einen dieser Schlüssel haben.

30
Ryan Lundy

Ich würde nur die FindAll-Methode für die List-Klasse verwenden. d.h .:

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

Nicht sicher, ob die Syntax genau zu Ihren Objekten passt, aber ich denke, Sie können sehen, wohin ich damit gehe.

4
BFree

Vielen Dank für die Jungs. 

Ich habe es geschafft, dies auf eine Zeile zu bringen:

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

Nochmals vielen Dank.

2
keeno

Sie können die Erweiterungsmethode "Except" verwenden (siehe http://msdn.Microsoft.com/en-us/library/bb337804.aspx ).

In deinem Code

var difference = people.Except(exclusions);
2
Fabrizio C.

Ich konnte nicht herausfinden, wie man dies in reinem MS LINQ macht, also schrieb ich meine eigene Erweiterungsmethode:

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

Passen Sie die Listentypen und Lambdas entsprechend an, und Sie können alles herausfiltern.

https://dotnetfiddle.net/6bMCvN

0
Wes

Ich würde so etwas tun, aber ich wette, es gibt einen einfacheren Weg. Ich denke, das SQL von Linqtosql würde eine Auswahl aus der Person Where Not Exist verwenden (Auswahl aus Ihrer Ausschlussliste).

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

In diesem LINQ wird die SQL für einen linken äußeren Join generiert und dann alle Ergebnisse übernommen, die in Ihrer Ausschlussliste keine Übereinstimmung finden.

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

lass mich wissen ob es funktioniert!

0
Noah