LINQ Where语句中如何检查列表是否包含另一个列表中的任何元素?

140
使用LINQ,我该如何检索一个属性列表与另一个列表匹配的项目列表?
以这个简单的示例伪代码为例:
List<Genres> listofGenres = new List<Genre>() { "action", "comedy" });   
var movies = _db.Movies.Where(p => p.Genres.Any() in listofGenres);

伪代码使得这个问题过于模糊,无法回答。首先,Genre的相等性定义不清楚。 - Gert Arnold
6个回答

245

听起来你想要:

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

我试图在搜索框中使用此查询,它会搜索Person_Name列中的任何字符,但是我遇到了这个错误:“'DbIntersectExpression需要具有兼容集合ResultTypes的参数”,所以我尝试从这里使用.StartWith, .EndsWith, .Contains,它可以工作,但是如何使用您的查询呢? - Shaiju T
@stom:我们没有足够的信息来帮助您解决问题 - 您应该提出一个新问题,并提供更多的上下文信息。 - Jon Skeet
@JonSkeet 我通常使用Contains方法来进行这种查询。看到你的回答后我很好奇,于是查看了内部实现并发现Intersect使用了Set。你能告诉我这两种方法之间的性能差异吗? - rebornx
9
使用Contains操作会导致时间复杂度为O(x*y),但空间复杂度为O(1),其中x是第一个集合的大小,y是第二个集合的大小。而使用Intersect操作时间复杂度为O(x+y),但空间复杂度为O(y)。它会从第二个集合构造一个哈希集来快速检查第一个集合中的任何项是否在其中。请参阅https://codeblog.jonskeet.uk/2010/12/30/reimplementing-linq-to-objects-part-16-intersect-and-build-fiddling/ 以获取详细信息。 - Jon Skeet
1
@SteveBoniface:我不会有这种期望,不会。我预计后者会稍微快一点,因为减少了间接性。 - Jon Skeet
显示剩余3条评论

73

您可以使用 Contains 查询来实现此目的:

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

9
如果你使用HashSet代替List来处理listofGenres,那么就可以这样做:

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

4
我猜这也可以像这样实现?
var movies = _db.Movies.TakeWhile(p => p.Genres.Any(x => listOfGenres.Contains(x));

"TakeWhile"与"Where"相比在性能和清晰度上是否更差?


TakeWhile 是一个不同的函数 - 当它找不到匹配项时,它将停止迭代。 - D Stanley

3
如果“Genre”是一个实体并且有其自己的属性,比如“Title”,请使用以下代码:
var listofGenresName = new List<string> { "action", "comedy" };
var movies = _db.Movies.Where(p => p.Genres.Any(x => listofGenresName.Any(g=> g == x.Title)));

2
或者像这样。
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();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接