如何从列表中删除空字符串,然后从列表中删除重复的值


81

可以说我有一个表中的一些列值的列表,如何删除空字符串和重复值。请参见以下代码:

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

这是我刚才编写的代码,但是Amiram的代码更优雅,因此我将选择答案,这是我的做法:

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"));
       }

了解RemoveAll()使dtList突变;删除的每个元素都将强制List在其使用的基础数组中的较高索引中重新排列元素。像Amiram的Where方法那样跳过它们会更快。
KeithS 2012年

Answers:


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

我假设空字符串和空格就像null。如果没有,则可以使用IsNullOrEmpty(允许空格),或者s != null


就一件事; 使用Distinct()进行重复数据删除效率相对较低,因为该方法必须假定最坏的情况。
KeithS 2012年

@KeithS我们知道关于此数据的哪些断言,哪些断言Distinct无法对其进行优化?
Servy 2012年

我们可以对列表进行排序,然后断言它已经排序,从而使重复数据删除算法呈线性;看我的答案。
KeithS 2012年

9

Amiram的答案是正确的,但是实现的Distinct()是N 2操作;对于列表中的每个项目,算法会将其与所有已处理的元素进行比较,如果唯一则返回它,否则返回它。我们可以做得更好。

可以按线性时间对已排序的列表进行重复数据删除;如果当前元素等于前一个元素,则忽略它,否则返回它。排序是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();

这将返回相同的元素;他们只是排序。


大。如果我没看错,请通过迭代元素来实际执行排序。您能想到一种使您的方法“懒惰”的方法吗?
2012年

不幸的是,大多数种类都需要对整个收藏品进行分类的知识。最后一个元素可能是第一个需要返回的元素。因此,必须评估输入的所有元素以产生输出的第一个元素。在找到其输出的下一个元素之后,我想到的唯一一种中断可能是SelectionSort变体,在这种情况下,我们回到了起点。
KeithS 2012年

此外,在我们的情况下,整个操作的结果是一个列表,首先需要“急切”执行。如果我们想将它作为IEnumerable使用并推迟执行,则可以利用该函数的实质,并将其放入实现IEnumerable的隐藏Iterator类中。
KeithS 2012年

Distinct使用散列,并且应比O(N ^ 2)更接近O(N)。来源
Risky Martin

……我会被吓死,的确如此。System.Linq.Set是Distinct使用的内部哈希表实现,假设您的项的GetHashCode()实现是有效的并且会产生均匀分布的哈希(默认实现会这样做),则访问时间将接近O(1 )。 。但是,哈希表确实存在内存问题。.NET的基本实现使用两个数组,一个为整数,另一个为链接项,每个数组最多等于集合中的项数,最坏的是等于该数。
KeithS 2012年

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

4
尽管这可行,但是Where子句更快,因为它不必更改输入集合。您正在最小化从列表中删除元素时必须执行的“移位”数量,但是Where不能从输入中删除任何内容;它只是跳过不匹配的元素。
KeithS 2012年

0

为了简化Amiram Korach的解决方案:

dtList.RemoveAll(s => string.IsNullOrWhiteSpace(s))

无需使用Distinct()或ToList()

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.