linq donde la lista contiene cualquiera en la lista

117

Usando linq, ¿cómo puedo recuperar una lista de elementos donde su lista de atributos coincide con otra lista?

Tome este simple ejemplo y pseudo código:

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

Respuestas:

202

Suena como que quieres:

var movies = _db.Movies.Where(p => p.Genres.Intersect(listOfGenres).Any());
Jon Skeet
fuente
Estaba tratando de usar esta consulta para el cuadro de búsqueda, busca cualquier carácter en la columna Person_Name, recibí este error: 'DbIntersectExpression requiere argumentos con una colección compatible ResultTypes', así que lo intenté .StartWith, .EndsWith, .Containsdesde aquí , funciona, pero ¿qué se puede hacer para usar su consulta?
shaijut
@stom: No tenemos suficiente información para ayudarte con eso; deberías hacer una nueva pregunta con mucho más contexto.
Jon Skeet
@JonSkeet Siempre uso el método Contains para este tipo de consultas. Tenía curiosidad al ver su respuesta y verifiqué la implementación interna y descubrí que Intersect usa Set. ¿Puede decirme la diferencia de rendimiento entre esos dos métodos?
rebornx
6
@Rebornx: El uso Containsrepetido termina como una operación O (x * y) en el tiempo, pero O (1) en el espacio, donde x es el tamaño de la primera colección e y es el tamaño de la segunda. El uso de Intersectes O (x + y) en el tiempo pero O (y) en el espacio: construye un conjunto de hash de la segunda colección, lo que agiliza la verificación de la inclusión de cualquier elemento de la primera colección. Consulte codeblog.jonskeet.uk/2010/12/30/… para más detalles
Jon Skeet
1
@SteveBoniface: No lo esperaba, no. Esperaría que este último sea un poco más rápido, ya que hay menos indirectas.
Jon Skeet
60

Puede utilizar una Containsconsulta para esto:

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

Si usa en HashSetlugar de Listfor listofGenrespuede hacer:

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

¿Supongo que esto también es posible así?

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

¿Es "TakeWhile" peor que "Where" en términos de rendimiento o claridad?

Trevor
fuente
TakeWhilees una función diferente: dejará de iterar cuando no encuentre una coincidencia.
D Stanley
1

O así

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
fuente