linkq, де список містить будь-який у списку


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 Я завжди використовую метод містять для таких запитів. Мені було цікаво, побачивши вашу відповідь і перевіривши внутрішню реалізацію і виявив, що Intersect використовує Set. Чи можете ви сказати мені різницю продуктивності між цими двома методами?
переродження

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замість 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 Стенлі

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();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.