LINQ: Виберіть, де об’єкт не містить елементів зі списку


78

Я борюся з синтаксисом LINQ тут ... думав, що викину його сюди. Я не можу знайти саме те, що я шукаю в іншому місці.

Добре, скажи, що я маю це

public class Bar
{
   public int BarId { get; set; }
}

public class Foo
{
   public List<Bar> BarList { get; set; }
}

List<Foo> fooBunch = GetABunchOfFoos(); //let's just assume I'm getting more than one
List<Foo> fooSelect = new List<Foo>;
List<Bar> filterBars = GetAFewBars(); //assume I'm getting like 2 or 3

fooSelect = (from f in fooBunch
             where !(from b in f.BarList select b.BarId).Contains(ITEM FROM filterBars.BarId)
             select f).ToList();

Отже, коротко кажучи, я хочу використовувати LINQ, щоб відфільтрувати свій список об'єктів на основі об'єктів з іншого списку. Сподіваюсь, це має сенс. Я думаю, що я просто загубився на частині Contains ... Я не знаю, як це написати.

Відповіді:


127

Загалом, ви шукаєте розширення "Крім".

var rejectStatus = GenerateRejectStatuses();
var fullList = GenerateFullList();
var rejectList = fullList.Where(i => rejectStatus.Contains(i.Status));
var filteredList = fullList.Except(rejectList);

У цьому прикладі GenerateRegectStatuses () повинен бути списком статусів, які ви хочете відхилити (або, більш конкретно, на основі вашого прикладу, a List<int>ідентифікаторів)


Це дуже близько ... фокус полягав би у створенні списку відхилення з динамічних статусів. Це було б більше схоже на те, де i => i.Status у (list <statuses>). Чи можу я зробити щось подібне? В основному ще одне твердження LINQ, я думаю?
farina

1
Безумовно, щоб побудувати rejectList, вам просто потрібно було б розробити спосіб отримати список відхилень, якого ви не хочете. Наприклад: var rejectList = fullList.Where(i => rejectStatuses.Contains(i.Status)); я оновлю свою оригінальну відповідь, щоб відобразити цю зміну.
Thebigcheeze

2
Як я можу це зробити лише одним рядком? Я розумію, що це може бути неможливо.
JustJohn

80

скиньте це у більш конкретну колекцію лише тих ідентифікаторів, які ви не хочете

var notTheseBarIds = filterBars.Select(fb => fb.BarId);

тоді спробуйте це:

fooSelect = (from f in fooBunch
             where !notTheseBarIds.Contains(f.BarId)
             select f).ToList();

або це:

fooSelect = fooBunch.Where(f => !notTheseBarIds.Contains(f.BarId)).ToList();

Приємно. мені більше подобається ця відповідь. +1
JoshYates1980

Ця відповідь краща за вибрану
Rarepuppers

Чисто і просто! Ніцца
Ката Хотеа

1
@Rarepuppers - Я витрачаю кілька хвилин, намагаючись зрозуміти прийняту відповідь, потім подивився тут, щоб побачити, що я вже набрав, перш ніж точно знав, чи так це працює ...
jleach

Це має бути прийнятою відповіддю. Я шукав, щоб зрозуміти, як це працює. Дякую тонна!
Xonshiz

5

Я не пробував цього, тому я нічого не гарантую, однак

foreach Bar f in filterBars
{
     search(f)
}
Foo search(Bar b)
{
    fooSelect = (from f in fooBunch
                 where !(from b in f.BarList select b.BarId).Contains(b.ID)
                 select f).ToList();

    return fooSelect;
}

2
З того, що я можу сказати, b.ID не компілюється. Здається, метод Contains втрачає контекст b.
farina

2
Ви використовуєте дві змінні з іменем b, і компілятор, мабуть, вважає це неоднозначним.
Джастін Морган,

4

Спробуйте цей простий LINQ:

//For a file list/array
var files = Directory.GetFiles(folderPath, "*.*", SearchOption.AllDirectories);

//simply use Where ! x.Contains
var notContain = files.Where(x => ! x.Contains(@"\$RECYCLE.BIN\")).ToList();

//Or use Except()
var containing = files.Where(x => x.Contains(@"\$RECYCLE.BIN\")).ToList();
    notContain = files.Except(containing).ToList();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.