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);
Pemenang
sumber

Jawaban:

202

Kedengarannya seperti yang Anda inginkan:

var movies = _db.Movies.Where(p => p.Genres.Intersect(listOfGenres).Any());
Jon Skeet
sumber
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));
Gelas pecah
sumber
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));
Efraim Bart
sumber
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?

Trevor
sumber
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();
Viacheslav Avsenev
sumber