2012-08-08 13 views
48

Diciamo che ho un elenco di alcuni valori di colonna provenienti da una tabella, come rimuovere stringhe vuote e valori duplicati. Si prega di consultare il seguente codice:come rimuovere stringhe vuote dall'elenco, quindi rimuovere i valori duplicati da un elenco

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

Questo è quello che ho codificato solo ora, ma ma il codice di Amiram è il modo più elegante, quindi mi scelgo la risposta qui è come ho fatto:

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

Capire che RemoveAll() muta dtList; ogni elemento rimosso rimuove l'Elenco per riorganizzare gli elementi in indici superiori nell'array sottostante che utilizza. Sarebbe più veloce semplicemente saltarli come fa Amiram con il suo metodo Where. – KeithS

risposta

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

Ho assunto una stringa vuota e gli spazi bianchi sono nulli. Se non è possibile utilizzare IsNullOrEmpty (consentire spazi bianchi), o s != null

+2

Mi piace questo bellissimo codice – EaterOfCode

+0

Solo una cosa; la deduplicazione con Distinct() è relativamente inefficiente perché il metodo deve assumere il caso peggiore. – KeithS

+0

@KeithS Quali asserzioni sappiamo di questi dati che 'Distinct' non consente di essere ottimizzato? – Servy

7

risposta di Amiram è corretta, ma distinta() come attuato è un N funzionamento; per ogni elemento nell'elenco, l'algoritmo lo confronta con tutti gli elementi già elaborati e lo restituisce se è univoco o lo ignora se non lo è. Possiamo fare di meglio

A ordinato elenco può essere dedotto in tempo lineare; se l'elemento corrente è uguale all'elemento precedente, ignorarlo, altrimenti restituirlo. L'ordinamento è NlogN, quindi, anche di dover ordinare la raccolta, si ottiene qualche 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(); 

Ciò restituisce gli stessi elementi; sono solo ordinati.

+0

Grande. Se non sbaglio, iterando gli elementi in realtà stai eseguendo l'ordine. Riesci a pensare a un modo per rendere il tuo metodo "pigro"? –

+0

Sfortunatamente, la maggior parte dei tipi richiede la conoscenza dell'intera collezione da ordinare; l'ultimo elemento potrebbe essere il primo che deve essere restituito. Quindi, tutti gli elementi dell'input devono essere valutati per produrre il primo elemento dell'output. L'unico tipo che posso pensare che possa essere interrotto dopo aver trovato il prossimo elemento del suo output è una variante SelectionSort, e in tal caso siamo tornati dove abbiamo iniziato. – KeithS

+0

Inoltre, nel nostro caso, il risultato dell'intera operazione è un elenco, che richiede un'esecuzione "appassionata" per cominciare. Se volessimo lavorare con esso come oggetto IEnumerable e rinviarne l'esecuzione, potremmo prendere la carne della funzione e inserirla in una classe Iterator nascosta che implementa IEnumerable. – KeithS

1

La soluzione di Amiram Korach è davvero ordinata. Ecco un'alternativa per motivi di versatilità.

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

Mentre funziona, la clausola Where è più veloce perché non deve modificare la collezione di input. Stai riducendo al minimo il numero di "turni" che devono essere eseguiti durante la rimozione di elementi dall'elenco, ma Dove non rimuove nulla dall'input; salta semplicemente gli elementi che non corrispondono. – KeithS

+0

Grazie per la spiegazione. – IneedHelp

Problemi correlati