linq,其中list包含列表中的任何一个


117

使用linq,如何检索其属性列表与另一个列表匹配的项目列表?

举一个简单的例子和​​伪代码:

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

Answers:


202

听起来像您想要的:

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

我试图在查询框中使用此查询,它搜索Person_Name列中的任何字符,但出现此错误:'DbIntersectExpression需要具有兼容集合ResultTypes的参数',所以我.StartWith, .EndsWith, .Contains这里尝试它的工作原理,但是可以使用您的查询做什么
shaijut 2015年

@stom:我们没有信息不足以帮你-你应该问一个新问题有很多更多的上下文。
乔恩·斯基特

@JonSkeet我总是将Contains方法用于此类查询。我对看到您的答案感到好奇,并检查了内部实现,发现Intersect使用Set。您能告诉我这两种方法的性能差异吗?
rebornx

6
@Rebornx:Contains反复使用最终会在时间上成为O(x * y)操作,但在空间上为O(1),其中x是第一个集合的大小,y是第二个集合的大小。使用的时间Intersect为O(x + y),但空间的为O(y)-它从第二个集合构造一个哈希集,这使它可以快速检查第一个集合中是否包含任何项。见codeblog.jonskeet.uk/2010/12/30/...的细节
乔恩斯基特

1
@SteveBoniface:我不希望如此,不。我希望后者会稍微快一点,因为间接调用较少。
Jon Skeet

60

您可以Contains为此使用查询:

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

5

如果您使用HashSet的,而不是List针对listofGenres你可以这样做:

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

3

我想这样也是可能的吗?

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

在性能或清晰度方面,“ TakeWhile”是否比“ Where”更糟?


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

1

或者像这样

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();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.