c# - multiple - ¿Eliminar instancias de una lista usando LINQ o Lambda?
linq c# (7)
Ahora vengo a una etapa para obtener todos mis datos como una lista en caché (objetos) y mi siguiente paso es eliminar algunas instancias de la lista.
Normalmente, lo haría eliminando así:
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
});
}
Para ser más específico, realmente construyo o llego a la lista BeRemvoedItems de una clase dinámica (no una clase formal definida). Por ejemplo, la clase T es algo así como MyClass y los códigos para eliminar son:
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;
});
}
Traté de buscar el método Remove()
en la interfaz IEnumerable
de MSDN, pero no puedo encontrar el método de Remove()
allí (tiene sentido que IEnumerable
se use solo para la enumeración). En la clase List, hay varios métodos Remove(...)
sobrecargados. No estoy seguro de si hay alguna forma alternativa de eliminar elementos de una lista mediante el uso de expresiones LINQ o Lambda.
Por cierto, pensé en una forma de hacer una consulta en una lista para obtener un subconjunto o una nueva lista IEnumerable
con las condiciones Where, similar a mover elementos de una lista. Sin embargo, prefiero eliminar elementos de mi lista en caché, y en algunos casos simplemente no puedo restablecer la propiedad de la lista en una clase a una nueva lista (por ejemplo, un conjunto privado).
Estoy de acuerdo con la sugerencia de Jared de filtrar ciertos artículos, pero parece que join
a Value1
sería un enfoque más eficiente:
var res = from item1 in list
join item2 in toBeRemovedList
on item1.Value1 equals item2.Value1
where item1.Value2 >= item2.Value2
select item1;
Actualización: Aparentemente no logro comprender la lectura, nuevo enfoque:
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;
});
Por supuesto, sería aún mejor si su lista para eliminar pudiera comenzar como un diccionario. En última instancia, solo estamos tratando de hacer que nuestra Value1
en Value1
más eficiente.
Para las colecciones que no son listas (no se puede exponer RemoveAll
), puede eliminar elementos con un solo liner.
Para reemplazar en línea, solo genere una lista de elementos para eliminar, luego ejecútelo y ejecute eliminar código.
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);
});
Para reemplazar en copia, solo genere un enumerable filtrado y devuelva una nueva copia.
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);
Puede usar el método RemoveAll :
MyClass one; //initialize MyClass
list.RemoveAll(item => one.Value1 == item.Value1 && one.Value2 < item.Value2);
Puede utilizar el método Where de LINQ para filtrar valores que no deberían formar parte de la lista. El resultado es un IEnumerable<T>
con los elementos eliminados.
var res = list.Where(item => !(one.Value1 == item.Value1 && one.Value2 < item.Value2));
Esto no actualizará la instancia de la List<T>
, sino que creará una nueva IEnumerable<T>
con los valores eliminados.
Si recibo la pregunta correctamente, produzco un conjunto único de dos listas.
Para esto, puedes usar lo siguiente
List list1; List list2;
List list3 = list1.Except (list2)
La lista3 contendrá elementos únicos.
Tal vez estás tratando de hacer algo como esto?
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);
}
Así es como logré resolver un problema al deshacerme de duplicados entre una List<ViewModel>
y una List<Model>
. Utilicé la función CheckIfWeRemoveThisOne
para verificar si el artículo. item.Number
pertenecía a algún otro elemento, usando la ID como característica definitoria. Si encontró otro elemento (un duplicado), en lugar de tratar de eliminarlo de la lista original (que en primer lugar List<ViewModel>
un List<Model>
y en mi función se me daba una List<ViewModel>
, entonces tenía mis dudas en cuanto a cómo podría hacerlo, de todos modos), acabo de crear una nueva lista, agregando el resultado si se comprobaba que estaba bien.
foreach(var item in toBeRemovedLItems) {
list.RemoveAll(one => one.Value1 == item.Value1 && one.Value2 < item.Value2);
}
Demasiado tarde otra vez. Oh bien.