linq dove list contiene qualsiasi in list


117

Utilizzando linq, come posso recuperare un elenco di elementi in cui il suo elenco di attributi corrisponde a un altro elenco?

Prendi questo semplice esempio e pseudo codice:

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

Risposte:


202

Sembra che tu voglia:

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

stavo cercando di utilizzare questa query per la casella di ricerca, cerca qualsiasi carattere nella colonna Person_Name, ho ricevuto questo errore: 'DbIntersectExpression richiede argomenti con la raccolta compatibile ResultTypes' quindi ho provato .StartWith, .EndsWith, .Containsda qui funziona, ma cosa si può fare per usare la tua query
shaijut

@stom: Non abbiamo abbastanza informazioni per aiutarti in questo - dovresti fare una nuova domanda con molto più contesto.
Jon Skeet

@ JonSkeet Uso sempre il metodo Contains per questo tipo di query. Ero curioso di vedere la tua risposta e di controllare l'implementazione interna e ho scoperto che Intersect usa Set. Puoi dirmi la differenza di prestazioni tra questi due metodi?
rebornx

6
@ Rebornx: L'uso Containsripetuto finisce come un'operazione O (x * y) nel tempo, ma O (1) nello spazio, dove x è la dimensione della prima raccolta ey è la dimensione della seconda. L'uso Intersectè O (x + y) nel tempo ma O (y) nello spazio: costruisce un hashset dalla seconda raccolta, che rende veloce il controllo dell'inclusione di qualsiasi elemento della prima raccolta. Vedi codeblog.jonskeet.uk/2010/12/30/… per i dettagli
Jon Skeet

1
@SteveBoniface: non me lo sarei aspettato, no. Mi aspetto che quest'ultimo sia leggermente più veloce, poiché c'è meno indiretto.
Jon Skeet,

60

Puoi usare una Containsquery per questo:

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

5

Se usi HashSetinvece di Listper listofGenrespuoi fare:

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

3

Immagino sia possibile anche così?

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

"TakeWhile" è peggio di "Where" in termini di performance o chiarezza?


TakeWhileè una funzione diversa: interromperà l'iterazione quando non trova una corrispondenza.
D Stanley

1

O così

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();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.