根据属性比较从列表中获取重复项列表

时间:2017-07-06 06:35:23

标签: c# linq

我有List<Demo>

public class Demo
{
    public Demo()
    {

    }

    public int Id { get; set; }
    public string Name { get; set; }
    public string Title { get; set; }
}

Id属性对于列表中的每个记录都是唯一的。

如何从原始List<Demo>获取List<Demo>,其中包含名称和标题相同的所有重复项。

到目前为止,我所做的只是一条记录:

List<Demo> demo = new List<Demo>();

demo.Add(new Demo()
{
    Id = 1,
    Name = "Demo",
    Title = "A"
});

demo.Add(new Demo()
{
    Id = 2,
    Name = "Demo",
    Title = "A"
});

demo.Add(new Demo()
{
    Id = 3,
    Name = "Demo",
    Title = "A"
});

demo.Add(new Demo()
{
    Id = 4,
    Name = "Demo1",
    Title = "A"
});

demo.Add(new Demo()
{
    Id = 5,
    Name = "Demo2",
    Title = "A"
});

然后我在做:

var duplicates = demo.GroupBy(t => new { t.Name, t.Title })
                     .Where(t => t.Count() > 1)
                     .Select(g => g.Key).ToList();

从上面的例子中我得到一个List<Demo>,前面有3个项目,其中id为1,2,3,因为名称和标题相同。

4 个答案:

答案 0 :(得分:9)

听起来你所缺少的只是一个SelectMany电话。目前,您正在创建所有相应的组并向下过滤到具有多个条目的组 - 但如果您需要单个平面列表,则需要将这些组展平回其元素:

var duplicates = demo
    .GroupBy(t => new { t.Name, t.Title })
    .Where(t => t.Count() > 1)
    .SelectMany(x => x) // Flatten groups to a single sequence
    .ToList();

请注意,此表示结果列表中的每个条目都具有相同的名称和标题。它确实意味着每个条目都有一个与至少一个其他条目共同的名称/标题组合。

答案 1 :(得分:2)

你快到了。

Groupby将序列分组。每个小组都有一些共同点:小组的Key。每个组都是一个序列,其中包含原始序列中与键匹配的所有元素。

您的密钥是new { t.Name, t.Title }。您的原始序列将被分为具有相同名称/标题的对象组:

  • 小组演示/ A 包含三个元素:Id = 1,Id = 2,Id = 3
  • 群组演示1 / A 仅包含元素ID = 4
  • 群组演示2 / A 仅包含元素ID = 5

分组后的Where会返回IGrouping的序列。此序列仅包含一个元素:唯一具有多个元素的组。这是具有密钥演示/ A的组。

您的规范不是IGrouping的序列(其中每个组是Demo的序列),而是Demo的一个列表,其中包含所有具有重复名称/标题的元素。

这意味着您必须在Where之后(在您的示例中此序列仅包含一个组)从所有组中获取元素,并将所有这些组连接成一个序列。这是由Enumerable.SelectMany

完成的
IEnumerable<Demo> duplicates = demo
    .GroupBy(demoElement => new {demoElement.Name, demoElement.Title})
    .Where(group => group.Skip(1).Any())
    .SelectMany(group => group);

SelectMany获取每个组的序列并将所有序列连接成一个序列。

顺便说一句,您是否注意到我没有使用Count()来检测是否有重复项,而是Skip(1).Any()。如果你的一个组有数百个元素,那么在第一个元素之后停止计数就足够了。计算所有元素以检测是否存在多个元素是浪费计算能力。

最后一个提示:如果您不确定是否需要,请不要使用ToList()。如果您的代码段的用户只想要第一个元素或前几个元素,那么如果您将所有元素计算到列表中,那将是一种浪费。尽可能长时间保持IEnumerable<Demo>

答案 2 :(得分:0)

如果你有超过1个标题并且名字相同,那么你想要的是什么。假设最后一个对象是Demo1A

var duplicates = demo.GroupBy(t => new { t.Name, t.Title }).Where(t => t.Count() > 1)
                     .Select(x => new { Count = x.Count(), Values = x.Select(y => y)})
                     .ToList();

这样做,为您提供计数和所有分组值(基于名称和标题)及其计数。

enter image description here

答案 3 :(得分:0)

下面的代码可以帮助您,

列出重复项= demo.GroupBy(grp =&gt; new {grp.Name,grp.Title})。SelectMany(selm =&gt; selm.Skip(1))。Distinct()。ToList();

根据您的预期答案,它正常运作。