2012-08-08 109 views
48

假設我有一個來自表的列值的列表,我如何刪除空字符串和重複值。請看下面的代碼:如何從列表中刪除空字符串,然後從列表中刪除重複的值

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

這是我已經編寫剛纔但卻阿米拉姆的代碼方式更優雅,所以我會選擇在這裏,答案是我是如何做的:

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

瞭解RemoveAll()mutates dtList;刪除的每個元素都會強制List重新排列其使用的底層數組中較高索引中的元素。只需像Amiram用他的Where方法跳過它一樣簡單。 – KeithS 2012-08-08 15:09:52

回答

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

我假定空字符串和空格都是空的。如果沒有,你可以使用IsNullOrEmpty(允許空格),或s != null

+2

我喜歡這個很好的代碼 – EaterOfCode 2012-08-08 14:49:31

+0

只是一件事;使用Distinct()進行重複數據刪除的效率相對較低,因爲該方法必須假設最差的情況。 – KeithS 2012-08-08 14:56:49

+0

@KeithS我們知道關於這個數據的哪些斷言,「Distinct」不允許它被優化? – Servy 2012-08-08 14:59:25

7

阿米拉姆的答案是正確的,但不同的()爲實施爲N 操作;對於列表中的每個項目,算法會將其與所有已處理的元素進行比較,如果它是唯一的,則將其返回,否則將其忽略。我們可以做得更好。

A 排序列表可以線性時間重複;如果當前元素等於前一個元素,則忽略它,否則返回它。排序是NlogN,所以即使有排序的集合,我們得到了一些好處:

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(); 

這將返回相同的元素;他們只是排序。

+0

太好了。如果我沒有錯,通過迭代實際執行排序的元素。你能想出一種方法使你的方法「懶惰」嗎? – 2012-08-08 15:08:41

+0

不幸的是,大多數種類都需要知道整個集合的排序;最後一個元素可能是第一個需要返回的元素。因此,必須評估輸入的所有元素才能生成輸出的第一個元素。我能想到的唯一種類可能會在找到它的輸出的下一個元素是SelectionSort變體後中斷,在那種情況下,我們又回到了開始的位置。 – KeithS 2012-08-08 15:14:45

+0

此外,在我們的例子中,整個操作的結果是一個列表,需要「熱切」執行。如果我們想將它作爲一個IEnumerable來使用並推遲執行它,那麼你可以把這個函數的內容放在一個隱藏的實現了IEnumerable的Iterator類中。 – KeithS 2012-08-08 15:19:08

1

Amiram Korach解決方案的確很整齊。爲了多功能性,這是一個替代方案。

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

儘管這會起作用,但Where子句更快,因爲它不必改變輸入集合。您將從列表中刪除元素時必須執行的「移位」數量降至最低,但在何處不會從輸入中移除任何內容;它只是跳過不匹配的元素。 – KeithS 2012-08-08 15:05:22

+0

感謝您的解釋。 – IneedHelp 2012-08-08 15:08:00