Reputation: 5107
Using linq, how can I retrieve a list of items where its list of attributes match another list?
Take this simple example and pseudo code:
List<Genres> listofGenres = new List<Genre>() { "action", "comedy" });
var movies = _db.Movies.Where(p => p.Genres.Any() in listofGenres);
Upvotes: 141
Views: 236253
Reputation: 29829
This is also a great use case for an extension method ContainsAny
like this:
public static class IEnumerableExtensions
{
/// <summary>
/// Determines whether a sequence contains any of the specified items.
/// </summary>
/// <typeparam name="T">The type of the elements in the sequences.</typeparam>
/// <param name="source">The sequence to search.</param>
/// <param name="items">The sequence of items to search for in the source sequence.</param>
/// <returns><c>true</c> if the source sequence contains any of the specified items; otherwise, <c>false</c>.</returns>
/// <remarks>
/// If either the source or items sequence is null, it will be treated as an empty sequence.
/// This method uses a HashSet for efficient lookup of items.
/// </remarks>
public static bool ContainsAny<T>(this IEnumerable<T> source, IEnumerable<T> items)
{
source ??= Array.Empty<T>();
items ??= Array.Empty<T>();
var itemSet = new HashSet<T>(items);
return source.Any(itemSet.Contains);
}
}
And then you can use like this:
var dbMovies = new List<Movie>
{
new Movie("Moana", new [] { "Animation", "Comedy" }),
new Movie("Mulan", new [] { "Animation", "Family" }),
new Movie("Brave", new [] { "Adventure", "Comedy" }),
};
var listOfGenres = new [] { "Comedy", "Western" };
var movies = dbMovies.Where(m => m.Genres.ContainsAny(listOfGenres));
Console.WriteLine(string.Join(", ", movies.Select(m => m.Title)));
// Moana, Brave
Searching for a list in a list in a list is already confusing enough, and this helps abstract some of he parts away to make the code more readable.
See Also: How to use Linq to check if a list of strings contains any string in a list
Upvotes: 0
Reputation: 621
If the Genre
is an Entity and has its own Properties such as Title
, use the following code:
var listofGenresName = new List<string> { "action", "comedy" };
var movies = _db.Movies.Where(p => p.Genres.Any(x => listofGenresName.Any(g=> g == x.Title)));
Upvotes: 2
Reputation: 194
If you use HashSet
instead of List
for listofGenres
you can do:
var genres = new HashSet<Genre>() { "action", "comedy" };
var movies = _db.Movies.Where(p => genres.Overlaps(p.Genres));
Upvotes: 9
Reputation: 1499770
Sounds like you want:
var movies = _db.Movies.Where(p => p.Genres.Intersect(listOfGenres).Any());
Upvotes: 251
Reputation: 1915
Or like this
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();
Upvotes: 2
Reputation: 51
I guess this is also possible like this?
var movies = _db.Movies.TakeWhile(p => p.Genres.Any(x => listOfGenres.Contains(x));
Is "TakeWhile" worse than "Where" in sense of performance or clarity?
Upvotes: 4
Reputation: 160852
You can use a Contains
query for this:
var movies = _db.Movies.Where(p => p.Genres.Any(x => listOfGenres.Contains(x));
Upvotes: 74