Подтвердить что ты не робот

Удалить экземпляры из списка с помощью LINQ или Lambda?

Теперь я пришел на сцену, чтобы получить все мои данные в виде списка в кеше (объектах), и следующее, что мне нужно сделать, это удалить некоторые экземпляры из списка.

Обычно я делал бы удаление следующим образом:

List<T> list;
List<T2> toBeRemovedItems;
// populate two lists
foreach(T2 item in toBeRemovedItems)
{
    list.Remove(delegate(T one) { 
        // build a condition based on item
        // return true or false
    });
}

Чтобы быть более конкретным, я фактически создаю или заполняю список toBeRemvoedItems динамического класса (а не формальный определенный класс). Например, класс T является чем-то вроде MyClass, а коды для удаления:

class MyClass<C> {
    public string Value1 { get; set; }
    public int Value2 { get; set; }
    public C ObjectC { get; set; }
}
....
List<MyClass<C>> list;
// populate list
// populate toBeRemovedItems. Here is an example of hard-coded codes:
var toBeRemovedLItems = new[] {
    new { Value1="a", Value2 = 1},
    new { Value2="x", Value2 = 10},
    ...
};
// toBeRemovedItems may be the result of Select from a collection
foreach(var item in toBeRemovedLItems)
{
    list.Remove(delegate(MyClass one) {
        return one.Value1 = item.Value1 && one.Value2 < item.Value2;
    });
}

Я попытался найти метод Remove() в интерфейсе IEnumerable из MSDN, но я не могу найти там метод Remove() (имеет смысл, что IEnumerable используется только для перечисления). В классе List имеется несколько перегруженных методов Remove(...). Я не уверен, есть ли альтернативные способы удаления элементов из списка с помощью выражений LINQ или Lambda?

Кстати, я подумал о том, как сделать запрос против списка, чтобы получить подмножество или новый список IEnumerable с условиями Where, аналогичными перемещающимся элементам из списка. Тем не менее, я предпочитаю удалять элементы из моего кэшированного списка, и в некоторых случаях я просто не могу использовать свойство списка reset в классе для нового списка (например, частный набор).

4b9b3361

Ответ 1

Вы можете использовать метод RemoveAll:

MyClass one; //initialize MyClass
list.RemoveAll(item => one.Value1 == item.Value1 && one.Value2 < item.Value2);

Ответ 2

Вы можете использовать метод LINQ Where для фильтрации значений, которые не должны быть частью списка. Результатом является IEnumerable<T> с удаленными элементами.

var res = list.Where(item => !(one.Value1 == item.Value1 && one.Value2 < item.Value2));

Это не будет обновлять исходный экземпляр List<T>, но вместо этого создаст новый IEnumerable<T> со значениями, удаленными.

Ответ 3

Если я правильно задаю вопрос, создадим уникальный набор из двух списков.

Для этого вы можете использовать следующие

Список list1; Список list2;

Список list3 = list1.Except(list2)

Список3 будет содержать уникальные элементы.

Ответ 4

Я согласен с предложением Jared о фильтрации определенных элементов, но похоже, что join on Value1 будет более эффективным:

var res = from item1 in list
          join item2 in toBeRemovedList
            on item1.Value1 equals item2.Value1
          where item1.Value2 >= item2.Value2
          select item1;

Обновление: По-видимому, я не понимаю понимания чтения - новый подход:

var removeDict = toBeRemovedList.ToDictionary(i => i.Value1, i => i.Value2);
list.RemoveAll(item => {
    int itemToRemoveValue2;
    if(removeDict.TryGetValue(item.Value1, out itemToRemoveValue2))
        return item.Value2 < itemToRemoveValue2;
    return false;
});

Конечно, было бы даже лучше, если бы ваш список для удаления мог начинаться как словарь. В конечном счете, мы просто пытаемся сделать наш матч на Value1 более эффективным.

Ответ 5

foreach(var item in toBeRemovedLItems) {   
   list.RemoveAll(one => one.Value1 == item.Value1 && one.Value2 < item.Value2); 
}

Слишком поздно. О, хорошо.

Ответ 6

Для коллекций, которые не являются списками (не могут выставлять RemoveAll), вы все равно можете удалять элементы с помощью одного слоя.

Чтобы заменить встроенный, просто сгенерируйте список элементов для удаления, затем выполните его и выполните удаление кода.

var dictionary = new Dictionary<string, string>(){{"foo", "0"}, {"boo", "1"}, {"goo", "1"}};
dictionary
    .Where(where_item =>
        ((where_item.Key == "foo") && (where_item.Value == "0"))
        || ((where_item.Key == "boo") && (where_item.Value == "1"))
    )
    .ToList()
    .ForEach(remove_item => {
        dictionary.Remove(remove_item.Key);
    });

Чтобы заменить в копии, просто сгенерируйте фильтрованное перечисление и верните новую копию.

var dictionary0 = new Dictionary<string, string>(){{"foo", "0"}, {"boo", "1"}, {"goo", "1"}};
var dictionary1 = dictionary0
    .Where(where_item =>
        ((where_item.Key == "foo") && (where_item.Value == "0"))
        || ((where_item.Key == "boo") && (where_item.Value == "1"))
    )
    .ToDictionary(each_item => each_item.Key, each_item => each_item.Value);

Ответ 7

Может быть, вы пытаетесь сделать что-то вроде этого?

List<T> firstList;
List<T2> toBeRemovedItems;
List<T> finalList;

foreach(T item in firstList)
{
    toBeRemovedItems = CheckIfWeRemoveThisOne(item.Number, item.Id);
    if (toBeRemovedItems == null && toBeRemovedItems.Count() == 0)
        finalList.Add(item);
}

Вот как мне удалось решить проблему, избавившись от дубликатов между List<ViewModel> и a List<Model>. Я использовал функцию CheckIfWeRemoveThisOne, чтобы проверить, принадлежит ли item.Number к другому элементу, используя идентификатор в качестве определяющего признака. Если он нашел другой элемент (дубликат), а не попытался удалить его из первоначального списка (который я возвращал List<Model> и в первую очередь получил List<ViewModel>), поэтому у меня были сомнения как бы я это ни делал), я только что построил новый список - добавив в него результат, если он был найден в порядке.