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);

Antworten:


202

Klingt wie Sie wollen:

var movies = _db.Movies.Where(p => p.Genres.Intersect(listOfGenres).Any());

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));

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));

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"?


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();
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.