2009-07-26 13 views
27

Ahora vienen una etapa para obtener todos mis datos como una lista en la memoria caché (objetos) y mi siguiente que tengo que hacer es quitar algunos casos de la lista.¿Eliminar instancias de una lista utilizando LINQ o Lambda?

Normalmente, lo haría eliminando de esta manera:

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íficos, en realidad construir o rellenar la lista toBeRemvoedItems de una clase dinámica (no una clase definida formal). Por ejemplo, la clase T es algo así como MyClass y códigos para la eliminación 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; 
    }); 
} 

Me trataron de buscar Remove() método en el IEnumerable interfaz de MSDN, pero no puedo encontrar el método de Remove() allí (que tiene sentido que IEnumerable se usa 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 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).

+0

Parece un idiota. Bueno, básicamente mencionaste todos los métodos posibles en la publicación en sí ... http://stackoverflow.com/questions/1120336/what-is-the-easiest-way-to-foreach-through-a-listt-removing-unwanted -objetos –

Respuesta

40

Se puede usar el método RemoveAll:

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

creo que en realidad es un método de la lista , no es un método de extensión – Jimmy

+0

¡Gracias! Actualizo mi publicación. –

+0

Según entiendo tus códigos, eliminas un artículo a la vez. De todos modos, tengo que repetir cada uno como la sugerencia de Rchard Hein. –

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

demasiado tarde otra vez. Oh bien.

+0

No estoy seguro de si es posible pasar dos parámetros a RemoveAll (lambda func) para eliminar un toBeRemovedItems, sin pasar por el bucle foreach. Por supuesto, ya es muy legible. –

21

Se pueden utilizar valores Donde método para filtrar de LINQ que no deben formar parte de la lista. El resultado es IEnumerable<T> con los elementos eliminados.

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

esto no actualizada del original List<T> ejemplo, pero en su lugar se creará una nueva IEnumerable<T> con los valores eliminados.

+0

¿Qué es el perf. golpear haciendo esto frente a un bucle para eliminar los elementos? –

4

Estoy de acuerdo con la sugerencia de filtrar ciertos artículos de Jared, pero parece que un join en 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: Al parecer, fallan en la comprensión de 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 nuestro partido en Value1 sea más eficiente.

+0

¿Es la combinación similar a SQL Intersect? o esta consulta LINQ así? –

+0

De todos modos, como mencioné en mi pregunta, si la propiedad de la lista no es configurable, no puedo usar esta estrategia. Es bueno solo que yo tenga el control de la lista. –

+0

Observado - respuesta actualizada. – dahlbyk

5

Si consigo la pregunta correctamente, para producir un conjunto único de dos listas.

Para ello, puede utilizar el siguiente lista1

Lista; Lista lista2;

Lista list3 = lista1.Excepto (list2)

La lista3 contendrá elementos únicos.

+0

Esta es la primera respuesta que aborda mi objetivo, que es eliminar y recibir la enumeración de los objetos que coinciden con la lambda. –

+0

Debe ser el mismo tipo de colección para que esto funcione. – vapcguy

1

Para las colecciones que no son listas (no se puede exponer RemoveAll), aún 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); 
0

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 me las arreglé para resolver un problema con la eliminación de duplicados entre un List<ViewModel> y una List<Model>. Usé la función CheckIfWeRemoveThisOne para verificar si el item.Number pertenecía a algún otro elemento, usando el ID como característica definitoria. Si encontró otro artículo (un duplicado), en lugar de tratar de eliminarlo de la lista original (que obtenía un List<Model> y me dieron un List<ViewModel> en mi función en primer lugar, entonces tenía mis dudas sobre cómo podría hacerlo, de todos modos), acabo de crear una nueva lista, agregando el resultado si se encontró que estaba bien.

Cuestiones relacionadas