linq where list contains any in list
Asked Answered
C

6

141

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);
Contravention answered 19/5, 2012 at 18:9 Comment(1)
Pseudo code makes this question too vague to answer. For one, it's not clear how equality of Genre is defined.Sacring
C
249

Sounds like you want:

var movies = _db.Movies.Where(p => p.Genres.Intersect(listOfGenres).Any());
Commend answered 19/5, 2012 at 18:10 Comment(8)
i was trying to use this query for search box, it searches any character in Person_Name column, i got this error :'DbIntersectExpression requires arguments with compatible collection ResultTypes' so i tried .StartWith, .EndsWith, .Contains from here it works, but what can be done to use your queryBowra
@stom: We don't have nearly enough information to help you with that - you should ask a new question with a lot more context.Commend
@JonSkeet I always use Contains method for these kind of queries. I was curious by seeing your answer and checked the internal implementation and found that Intersect uses Set. Can you tell me the performance difference between those two methods?A
@Rebornx: Using Contains repeatedly ends up as an O(x*y) operation in time, but O(1) in space, where x is the size of the first collection and y is the size of the second. Using Intersect is O(x+y) in time but O(y) in space - it constructs a hashset from the second collection, which makes it quick to check for inclusion for any item from the first collection. See codeblog.jonskeet.uk/2010/12/30/… for detailsCommend
@JonSkeet Is there any significant performance implications when choosing to "chain" .Where() with .Any()? Since .Any() has an overload that takes a predicate, is it better to just use that overload instead of chaining?Thriller
@SteveBoniface: Note that this isn't calling .Where(...).Any() - it's calling .Where(x => x...Any()). The Any is within the predicate.Commend
@JonSkeet Yes, that's important to note. Generally, would there ever be a reason to do something like: myCollection.Where(x => <<some predicate>>).Any() when one can just do myCollection.Any(x => <<some predicate>>) ? Are there major performance differences between the two?Thriller
@SteveBoniface: I wouldn't expect so, no. I'd expect the latter to be very slightly faster, as there's less indirection.Commend
P
74

You can use a Contains query for this:

var movies = _db.Movies.Where(p => p.Genres.Any(x => listOfGenres.Contains(x));
Peery answered 19/5, 2012 at 18:13 Comment(0)
P
9

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));
Portsalut answered 15/11, 2018 at 1:33 Comment(0)
Z
4

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?

Zak answered 17/7, 2013 at 8:56 Comment(1)
TakeWhile is a different function - it will stop iterating when it does not find a match.Strow
H
2

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();
Hoff answered 28/8, 2014 at 12:22 Comment(0)
D
2

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)));
Dispenser answered 4/12, 2021 at 11:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.