linq, где список содержит любое в списке

117

Как с помощью linq получить список элементов, список атрибутов которых соответствует другому списку?

Возьмите этот простой пример и псевдокод:

List<Genres> listofGenres = new List<Genre>() { "action", "comedy" });   
var movies = _db.Movies.Where(p => p.Genres.Any() in listofGenres);
Виктор
источник

Ответы:

202

Похоже, вы хотите:

var movies = _db.Movies.Where(p => p.Genres.Intersect(listOfGenres).Any());
Джон Скит
источник
я пытался использовать этот запрос для окна поиска, он ищет любой символ в колонке PERSON_NAME, я получил эту ошибку: «DbIntersectExpression требует аргументов с совместимым ResultTypes сбора» , поэтому я попытался .StartWith, .EndsWith, .Containsиз здесь он работает, но то , что можно сделать , чтобы использовать запрос
Shaijut
@stom: У нас нет почти достаточно информации , чтобы помочь вам с тем, что - вы должны задать новый вопрос с гораздо больше контекста.
Джон Скит,
@JonSkeet Я всегда использую метод Contains для такого рода запросов. Мне было любопытно увидеть ваш ответ, я проверил внутреннюю реализацию и обнаружил, что Intersect использует Set. Можете ли вы сказать мне разницу в производительности между этими двумя методами?
rebornx
6
@Rebornx: Containsповторное использование заканчивается операцией O (x * y) во времени, но O (1) в пространстве, где x - размер первой коллекции, а y - размер второй. Используется IntersectO (x + y) во времени, но O (y) в пространстве - он создает хэш-набор из второй коллекции, что позволяет быстро проверять включение любого элемента из первой коллекции. См codeblog.jonskeet.uk/2010/12/30/... подробности
Джон Скит
1
@SteveBoniface: Я бы этого не ожидал, нет. Я бы ожидал, что последний будет немного быстрее, так как косвенных указаний меньше.
Джон Скит,
60

Для этого можно использовать Containsзапрос:

var movies = _db.Movies.Where(p => p.Genres.Any(x => listOfGenres.Contains(x));
Разбитое стекло
источник
5

Если вы используете HashSetвместо Listfor, 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();
Вячеслав Авсенев
источник