LINQ: Wählen Sie aus, wo das Objekt keine Elemente aus der Liste enthält

77

Ich habe hier Probleme mit der LINQ-Syntax ... dachte, ich würde sie hier rauswerfen. Ich kann nirgendwo anders genau das finden, wonach ich suche.

OK, sag ich habe das:

public class Bar
{
   public int BarId { get; set; }
}

public class Foo
{
   public List<Bar> BarList { get; set; }
}

List<Foo> fooBunch = GetABunchOfFoos(); //let's just assume I'm getting more than one
List<Foo> fooSelect = new List<Foo>;
List<Bar> filterBars = GetAFewBars(); //assume I'm getting like 2 or 3

fooSelect = (from f in fooBunch
             where !(from b in f.BarList select b.BarId).Contains(ITEM FROM filterBars.BarId)
             select f).ToList();

Kurz gesagt, ich möchte LINQ verwenden, um meine Liste von Objekten basierend auf Objekten aus einer anderen Liste herauszufiltern. Ich hoffe das macht Sinn. Ich glaube, ich bin nur im Contains-Teil verloren ... Ich weiß nicht, wie ich das schreiben soll.

Farina
quelle

Antworten:

126

Im Allgemeinen suchen Sie nach der Erweiterung "Außer".

var rejectStatus = GenerateRejectStatuses();
var fullList = GenerateFullList();
var rejectList = fullList.Where(i => rejectStatus.Contains(i.Status));
var filteredList = fullList.Except(rejectList);

In diesem Beispiel sollte GenerateRegectStatuses () die Liste der Status sein, die Sie ablehnen möchten (oder konkreter ausgedrückt anhand Ihres Beispiels eine List<int>der IDs).

Thebigcheeze
quelle
Das ist wirklich nah ... der Trick wäre, die RejectList aus dynamischen Status zu erstellen. Es wäre eher so, als ob i => i.Status in (Liste <Status>). Kann ich so etwas machen? Grundsätzlich eine andere LINQ-Anweisung, denke ich?
Farina
1
Um die Ablehnungsliste zu erstellen, müssten Sie nur einen Weg finden, um eine Liste der Ablehnungen zu erhalten, die Sie nicht möchten. Zum Beispiel: var rejectList = fullList.Where(i => rejectStatuses.Contains(i.Status)); Ich werde meine ursprüngliche Antwort aktualisieren, um diese Änderung widerzuspiegeln.
Thebigcheeze
2
Wie würde ich das in nur einer Zeile machen? Ich verstehe, dass es möglicherweise nicht möglich ist.
JustJohn
78

Speichern Sie dies in einer spezifischeren Sammlung nur der IDs, die Sie nicht möchten

var notTheseBarIds = filterBars.Select(fb => fb.BarId);

dann versuchen Sie dies:

fooSelect = (from f in fooBunch
             where !notTheseBarIds.Contains(f.BarId)
             select f).ToList();

oder dieses:

fooSelect = fooBunch.Where(f => !notTheseBarIds.Contains(f.BarId)).ToList();
Jäger
quelle
Nett. Ich mag diese Antwort besser. +1
JoshYates1980
Diese Antwort ist besser als die ausgewählten
Rarepuppers
Sauber und einfach! Schön
Cata Hotea
@ Rarepuppers - Ich verbringe ein paar Minuten damit, die akzeptierte Antwort zu verstehen, und habe dann hier nachgeschlagen, was ich bereits eingegeben habe, bevor ich sicher war, ob es so funktioniert ...
Jleach
Dies sollte die akzeptierte Antwort sein. Ich habe versucht zu verstehen, wie es funktioniert. Danke vielmals!
Xonshiz
5

Ich habe dies nicht versucht, daher garantiere ich jedoch nichts

foreach Bar f in filterBars
{
     search(f)
}
Foo search(Bar b)
{
    fooSelect = (from f in fooBunch
                 where !(from b in f.BarList select b.BarId).Contains(b.ID)
                 select f).ToList();

    return fooSelect;
}
Tony der Löwe
quelle
2
Nach allem, was ich sagen kann, wird b.ID nicht kompiliert. Die Contains-Methode scheint den Kontext von b zu verlieren.
Farina
2
Sie verwenden zwei Variablen mit dem Namen b, und der Compiler findet sie wahrscheinlich nicht eindeutig.
Justin Morgan
4

Probieren Sie diesen einfachen LINQ aus:

//For a file list/array
var files = Directory.GetFiles(folderPath, "*.*", SearchOption.AllDirectories);

//simply use Where ! x.Contains
var notContain = files.Where(x => ! x.Contains(@"\$RECYCLE.BIN\")).ToList();

//Or use Except()
var containing = files.Where(x => x.Contains(@"\$RECYCLE.BIN\")).ToList();
    notContain = files.Except(containing).ToList();
Alex
quelle