从IEnumerable中获取非唯一元素

19
我有一个名为Item的类。Item具有名为ItemCode的标识符属性,其类型为字符串。我想从一个Item列表中获取所有非唯一的Items的列表。
例子:
List<Item> itemList = new List<Item>()
{
   new Item("code1", "description1"),
   new Item("code2", "description2"),
   new Item("code2", "description3"),
};
我想要一个包含最后两个条目的列表。
如果我使用以下代码:
var distinctItems = itemsList.Distinct();

我得到了一份独特项的列表,这很好,但我想要几乎相反的结果。我可以从原始列表中减去独特列表,但那并不包含所有重复项,仅包含每个重复项的一个实例。

我已经尝试过了,但找不到优雅的解决方案。任何指针或帮助都将非常感激。谢谢!

我的环境是3.5,所以可以使用LINQ。

4个回答

23

我的看法:

var distinctItems = 
    from list in itemsList
    group list by list.ItemCode into grouped
    where grouped.Count() > 1
    select grouped;

感谢Magnus(和Thomas),我从未想过要使用GroupBy。 - RichK
1
我建议将变量名更改为nonDistinctItems以增加清晰度。虽然如此,这是一个很好的答案,我用它作为解决方案。 - feyd

20
作为扩展方法:
public static IEnumerable<T> NonDistinct<T, TKey> (this IEnumerable<T> source, Func<T, TKey> keySelector)
{
   return source.GroupBy(keySelector).Where(g => g.Count() > 1).SelectMany(r => r);
}

2

您可能想尝试使用group by运算符。其想法是按ItemCode对它们进行分组,并取具有多个成员的组,类似于:

var grouped = from i in itemList
              group i by i.ItemCode into g
              select new { Code = g.Key, Items = g };

var result = from g in grouped 
             where g.Items.Count() > 1;

我无法编译这个程序。它抱怨“group by”和“into”语句。 - RichK
我忘记在“group”和“by”之间加上“i”了。现在已经修正过来了,但本质上与Magnus所写的一样。 - Tomas Vana

0
我建议编写一个定制的扩展方法,类似这样:
static class RepeatedExtension
{
    public static IEnumerable<T> Repeated<T>(this IEnumerable<T> source)
    {
        var distinct = new Dictionary<T, int>();
        foreach (var item in source)
        {
            if (!distinct.ContainsKey(item))
                distinct.Add(item, 1);
            else
            {
                if (distinct[item]++ == 1) // only yield items on first repeated occurence
                    yield return item;
            }                    
        }
    }
}

你还需要重写Item类的Equals()方法,以便通过它们的代码正确比较项目。

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