linq di mana daftar berisi apa saja dalam daftar


117

Dengan menggunakan linq, bagaimana saya dapat mengambil daftar item yang daftar atributnya cocok dengan daftar lain?

Ambil contoh sederhana dan kode pseudo ini:

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

Jawaban:


202

Kedengarannya seperti yang Anda inginkan:

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

saya mencoba menggunakan kueri ini untuk kotak pencarian, itu mencari karakter apa pun di kolom Person_Name, saya mendapat kesalahan ini: 'DbIntersectExpression memerlukan argumen dengan koleksi yang kompatibel ResultTypes' jadi saya mencoba .StartWith, .EndsWith, .Containsdari sini berfungsi, tetapi apa yang bisa dilakukan untuk menggunakan kueri Anda
shaijut

@stom: Kami hampir tidak memiliki cukup informasi untuk membantu Anda - Anda harus mengajukan pertanyaan baru dengan konteks yang lebih banyak .
Jon Skeet

@ JonSkeet Saya selalu menggunakan metode Berisi untuk kueri semacam ini. Saya penasaran dengan melihat jawaban Anda dan memeriksa implementasi internal dan menemukan bahwa Intersect menggunakan Set. Dapatkah Anda memberi tahu saya perbedaan kinerja antara kedua metode tersebut?
rebornx

6
@Rebornx: Menggunakan Containsberulang kali berakhir sebagai operasi O (x * y) dalam waktu, tetapi O (1) dalam ruang, di mana x adalah ukuran koleksi pertama dan y adalah ukuran koleksi kedua. Menggunakan Intersectadalah O (x + y) dalam waktu tetapi O (y) dalam ruang - itu membangun hashset dari koleksi kedua, yang membuatnya cepat untuk memeriksa penyertaan item apa pun dari koleksi pertama. Lihat codeblog.jonskeet.uk/2010/12/30/… untuk detailnya
Jon Skeet

1
@SteveBoniface: Saya tidak berharap begitu, tidak. Saya berharap yang terakhir menjadi sangat sedikit lebih cepat, karena ada lebih sedikit tipuan.
Jon Skeet

60

Anda dapat menggunakan Containskueri untuk ini:

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

5

Jika Anda menggunakan HashSetalih-alih Listuntuk listofGenresAnda dapat melakukan:

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

3

Saya kira ini juga mungkin seperti ini?

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

Apakah "TakeWhile" lebih buruk daripada "Where" dalam arti performa atau kejelasan?


TakeWhileadalah fungsi yang berbeda - ini akan berhenti mengulang jika tidak menemukan kecocokan.
D Stanley

1

Atau seperti ini

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();
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.