linq wobei list eine beliebige in list enthält

117

Wie kann ich mit linq eine Liste von Elementen abrufen, deren Attributliste mit einer anderen Liste übereinstimmt?

Nehmen Sie dieses einfache Beispiel und den Pseudocode:

List<Genres> listofGenres = new List<Genre>() { "action", "comedy" });   
var movies = _db.Movies.Where(p => p.Genres.Any() in listofGenres);
Sieger
quelle

Antworten:

202

Klingt wie Sie wollen:

var movies = _db.Movies.Where(p => p.Genres.Intersect(listOfGenres).Any());
Jon Skeet
quelle
Ich habe versucht, diese Abfrage für das Suchfeld zu verwenden. Sie durchsucht jedes Zeichen in der Spalte Person_Name. Ich habe den folgenden Fehler erhalten: 'DbIntersectExpression erfordert Argumente mit kompatibler Sammlung ResultTypes', also habe ich .StartWith, .EndsWith, .Containsvon hier aus versucht , dass es funktioniert, aber was kann getan werden, um Ihre Abfrage zu verwenden
Shaijut
@stom: Wir haben fast nicht genug Informationen, um Ihnen dabei zu helfen - Sie sollten eine neue Frage mit viel mehr Kontext stellen.
Jon Skeet
@ JonSkeet Ich verwende immer die Contains-Methode für diese Art von Abfragen. Ich war neugierig, als ich Ihre Antwort sah und die interne Implementierung überprüfte und feststellte, dass Intersect Set verwendet. Können Sie mir den Leistungsunterschied zwischen diesen beiden Methoden erklären?
Rebornx
6
@Rebornx: Die Containswiederholte Verwendung endet als O (x * y) -Operation in der Zeit, aber O (1) im Raum, wobei x die Größe der ersten Sammlung und y die Größe der zweiten ist. Die Verwendung Intersectist O (x + y) in der Zeit, aber O (y) im Raum - es wird ein Hashset aus der zweiten Sammlung erstellt, wodurch schnell geprüft werden kann, ob Elemente aus der ersten Sammlung enthalten sind. Siehe codeblog.jonskeet.uk/2010/12/30/… für Details
Jon Skeet
1
@SteveBoniface: Das würde ich nicht erwarten, nein. Ich würde erwarten, dass Letzteres etwas schneller ist, da es weniger Indirektion gibt.
Jon Skeet
60

Sie können hierfür eine ContainsAbfrage verwenden:

var movies = _db.Movies.Where(p => p.Genres.Any(x => listOfGenres.Contains(x));
Glassplitter
quelle
5

Wenn Sie HashSetanstelle von Listfür verwenden listofGenres, können Sie Folgendes tun:

var genres = new HashSet<Genre>() { "action", "comedy" };   
var movies = _db.Movies.Where(p => genres.Overlaps(p.Genres));
Efraim Bart
quelle
3

Ich denke das ist auch so möglich?

var movies = _db.Movies.TakeWhile(p => p.Genres.Any(x => listOfGenres.Contains(x));

Ist "TakeWhile" in Bezug auf Leistung oder Klarheit schlechter als "Where"?

Trevor
quelle
TakeWhileist eine andere Funktion - sie hört auf zu iterieren, wenn keine Übereinstimmung gefunden wird.
D Stanley
1

Oder so

class Movie
{
  public string FilmName { get; set; }
  public string Genre { get; set; }
}

...

var listofGenres = new List<string> { "action", "comedy" };

var Movies = new List<Movie> {new Movie {Genre="action", FilmName="Film1"},
                new Movie {Genre="comedy", FilmName="Film2"},
                new Movie {Genre="comedy", FilmName="Film3"},
                new Movie {Genre="tragedy", FilmName="Film4"}};

var movies = Movies.Join(listofGenres, x => x.Genre, y => y, (x, y) => x).ToList();
Viacheslav Avsenev
quelle