查询列表中的重复项。

6

我在一个.NET 3.5项目中有一个字符串列表,其中包含成千上万个字符串,但为了简洁起见,我们假设它只有5个字符串。

List<string> lstStr = new List<string>() {
            "Apple", "Banana", "Coconut", "Coconut", "Orange"};

假设列表已排序(如上所述)。我需要的是一个LINQ查询,它将删除所有不是重复项的字符串。因此,结果将使我得到只包含两个“Coconut”字符串的列表。
这可以用LINQ查询实现吗?如果不能,那么我将不得不使用一些复杂的for循环,我可以做到,但除非必须,否则我不想这样做。
4个回答

4

var dupes = lstStr.Where(x => lstStr.Count(y => y == x) > 1);

或者

var dupes = lstStr.Where((x,i) => (   (i > 0 && x==lstStr[i-1]) 
                                   || (i < lstStr.Count-1 && x==lstStr[i+1]));

请注意,第一个枚举每个元素的列表需要O(n²)时间(但不假定已排序的列表)。第二个是O(n)(并假定已排序的列表)。

4

这里有一个从字符串数组中查找重复项的代码:

int[] listOfItems = new[] { 4, 2, 3, 1, 6, 4, 3 };
var duplicates = listOfItems
    .GroupBy(i => i)
    .Where(g => g.Count() > 1)
    .Select(g => g.Key);
foreach (var d in duplicates)
    Console.WriteLine(d);

1

这应该可以工作,并且是O(N)而不是其他答案的O(N^2)。(请注意,这确实使用了列表已排序的事实,因此这确实是一个要求)。

IEnumerable<T> OnlyDups<T>(this IEnumerable<T> coll) 
   where T: IComparable<T>
{
     IEnumerator<T> iter = coll.GetEnumerator();
     if (iter.MoveNext())
     {
         T last = iter.Current;
         while(iter.MoveNext())
         {
             if (iter.Current.CompareTo(last) == 0)
             {
                  yield return last;
                  do 
                  {
                       yield return iter.Current;
                  }
                  while(iter.MoveNext() && iter.Current.CompareTo(last) == 0);
             }
             last = iter.Current;
         }
}

使用方法如下:

IEnumerable<string> onlyDups = lstStr.OnlyDups();

或者

List<string> onlyDups = lstStr.OnlyDups().ToList();

@McKay:是的,但是OP说可以假设列表已经排序。 - James Curran
@McKey(修改后的问题):严格来说不是,但它确实保持了LINQ风格的接口,并且可以作为更大的LINQ语句的一部分使用。 - James Curran

0
var temp = new List<string>();

foreach(var item in list)
{
    var stuff = (from m in list
                 where m == item
                 select m);
    if (stuff.Count() > 1)
    {
        temp = temp.Concat(stuff);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接