linq nơi danh sách chứa bất kỳ trong danh sách


117

Sử dụng linq, làm cách nào tôi có thể truy xuất danh sách các mục mà danh sách các thuộc tính của nó khớp với một danh sách khác?

Lấy ví dụ đơn giản và mã giả này:

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

Câu trả lời:


202

Có vẻ như bạn muốn:

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

tôi đã cố gắng sử dụng truy vấn này cho hộp tìm kiếm, nó tìm kiếm bất kỳ ký tự nào trong cột Tên_người, tôi gặp lỗi này: 'DbIntersectExpression yêu cầu đối số với bộ sưu tập tương thích ResultTypes' vì vậy tôi đã thử .StartWith, .EndsWith, .Containstừ đây nó hoạt động, nhưng có thể làm gì để sử dụng truy vấn của bạn
shaijut

@stom: Chúng tôi gần như không có đủ thông tin để giúp bạn điều đó - bạn nên đặt một câu hỏi mới với nhiều ngữ cảnh hơn.
Jon Skeet

@JonSkeet Tôi luôn sử dụng phương thức Chứa cho những loại truy vấn này. Tôi rất tò mò khi xem câu trả lời của bạn và đã kiểm tra việc triển khai nội bộ và thấy rằng Intersect sử dụng Set. Bạn có thể cho tôi biết sự khác biệt về hiệu suất giữa hai phương pháp đó?
rebornx

6
@Rebornx: Sử dụng Containslặp đi lặp lại kết thúc là một phép toán O (x * y) trong thời gian, nhưng O (1) trong không gian, trong đó x là kích thước của tập hợp đầu tiên và y là kích thước của tập hợp thứ hai. Sử dụng IntersectO (x + y) trong thời gian nhưng O (y) trong không gian - nó tạo một bộ băm từ bộ sưu tập thứ hai, giúp nhanh chóng kiểm tra xem có đưa vào bất kỳ mục nào từ bộ sưu tập đầu tiên hay không. Xem codeblog.jonskeet.uk/2010/12/30/… để biết chi tiết
Jon Skeet

1
@SteveBoniface: Tôi sẽ không mong đợi như vậy, không. Tôi hy vọng sau này sẽ nhanh hơn một chút, vì ít bị chuyển hướng hơn.
Jon Skeet

60

Bạn có thể sử dụng một Containstruy vấn cho việc này:

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

5

Nếu bạn sử dụng HashSetthay vì Listcho listofGenresbạn có thể làm:

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

3

Tôi đoán điều này cũng có thể như thế này?

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

"TakeWhile" có tệ hơn "Where" về hiệu suất hay độ rõ ràng không?


TakeWhilelà một hàm khác - nó sẽ ngừng lặp lại khi không tìm thấy kết quả phù hợp.
D Stanley

1

Hay như thế này

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();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.