2012-08-08 19 views
48

Digamos que tengo una lista de algunos valores de columna procedentes de una tabla, cómo elimino cadenas vacías y valores duplicados. Consulte el siguiente código:cómo eliminar cadenas vacías de la lista, luego eliminar valores duplicados de una lista

List<string> dtList = dtReportsList.AsEnumerable().Select(dr => dr.Field<string>("column1")).ToList(); 

Esto es lo que he codificado situado justo ahora, pero pero el código de Amiram es la forma más elegante, así que voy a elegir esa respuesta aquí es cómo lo hice:

DataTable dtReportsList = someclass.GetReportsList(); 

     if (dtReportsList.Rows.Count > 0) 
     { 


      List<string> dtList = dtReportsList.AsEnumerable().Select(dr => dr.Field<string>("column1")).ToList(); 
      dtList.RemoveAll(x=>x == ""); 
      dtList = dtList.Distinct().ToList();   

      rcboModule.DataSource = dtList; 
      rcboModule.DataBind();    
      rcboModule.Items.Insert(0, new RadComboBoxItem("All", "All")); 


     } 
+0

Comprender que RemoveAll() mutates dtList; cada elemento que se elimina obliga a la Lista a reorganizar elementos en índices superiores en la matriz subyacente que utiliza. Sería más rápido simplemente omitirlos como lo hace Amiram con su método Where. – KeithS

Respuesta

119
dtList = dtList.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToList() 

Supuse que la cadena vacía y los espacios en blanco son nulos. Si no puede utilizar IsNullOrEmpty (permitir que los espacios en blanco), o s != null

+2

Me gusta este código muy bueno – EaterOfCode

+0

Solo una cosa; la deduping con Distinct() es relativamente ineficiente porque el método debe asumir el peor de los casos. – KeithS

+0

@KeithS ¿Qué afirmaciones conocemos acerca de estos datos que 'Distinct' no permite optimizar? – Servy

7

respuesta de Amiram es correcta, pero distinto() tal como se aplica es una N operación; para cada elemento de la lista, el algoritmo lo compara con todos los elementos ya procesados ​​y lo devuelve si es único o lo ignora si no es así. Podemos hacerlo mejor.

A ordenados la lista se puede deducir en tiempo lineal; si el elemento actual es igual al elemento anterior, ignórelo; de lo contrario, devuélvalo. La clasificación es NlogN, por lo que incluso tener que ordenar la colección, obtenemos algún beneficio:

public static IEnumerable<T> SortAndDedupe<T>(this IEnumerable<T> input) 
{ 
    var toDedupe = input.OrderBy(x=>x); 

    T prev; 
    foreach(var element in toDedupe) 
    { 
     if(element == prev) continue; 

     yield return element; 
     prev = element;  
    } 
} 

//Usage 
dtList = dtList.Where(s => !string.IsNullOrWhitespace(s)).SortAndDedupe().ToList(); 

Esto devuelve los mismos elementos; solo están ordenados

+0

Genial. Si no estoy equivocado, al iterar los elementos, en realidad está realizando el pedido. ¿Puedes pensar en una forma de hacer que tu método sea "flojo"? –

+0

Desafortunadamente, la mayoría de los tipos requieren el conocimiento de toda la colección para clasificar; el último elemento podría ser el primero que debe devolverse. Entonces, todos los elementos de la entrada deben ser evaluados para producir el primer elemento de la salida. El único tipo que puedo pensar que podría ser interrumpido después de encontrar el siguiente elemento de su salida es una variante SelectionSort, y en ese caso estamos de vuelta donde comenzamos. – KeithS

+0

Además, en nuestro caso, el resultado de toda la operación es una lista, que requiere una ejecución "ansiosa" para comenzar. Si quisiéramos trabajar con él como un IEnumerable y diferir la ejecución del mismo, podría tomar el control de la función y ponerlo en una clase Iterator oculta que implemente IEnumerable. – KeithS

1

La solución Amiram Korach está de hecho ordenada. Aquí hay una alternativa por la versatilidad.

var count = dtList.Count; 
// Perform a reverse tracking. 
for (var i = count - 1; i > -1; i--) 
{ 
    if (dtList[i]==string.Empty) dtList.RemoveAt(i); 
} 
// Keep only the unique list items. 
dtList = dtList.Distinct().ToList(); 
+3

Si bien esto funcionaría, la cláusula Where es más rápida porque no tiene que mutar la colección de entrada. Está minimizando el número de "cambios" que se deben realizar cuando se eliminan elementos de la lista, pero donde no se elimina nada de la entrada; simplemente se salta los elementos que no coinciden. – KeithS

+0

Gracias por la explicación. – IneedHelp

Cuestiones relacionadas