LINQ查询以检测对象列表中的重复属性

时间:2009-12-16 10:41:58

标签: c# .net linq linq-to-objects

我有一个对象列表。这些对象由自定义类组成,该类基本上包含两个字符串字段String1String2

我需要知道的是,如果这些字符串中的任何字符串在该列表中重复。所以我想知道objectA.String1 == objectB.String1ObjectA.String2 == ObjectB.String2ObjectA.String1 == ObjectB.String“还是ObjectA.String2 == ObjectB.String1

另外,我想将包含重复字符串的每个对象标记为具有重复字符串(对象上有bool HasDuplicate)。

因此,当重复检测已经运行时,我想简单地按照这样的方式遍历列表:

foreach (var item in duplicationList)
    if (item.HasDuplicate)
        Console.WriteLine("Duplicate detected!");

这似乎是用LINQ解决的一个很好的问题,但我不能为我的生活找出一个好的查询。所以我用'好老'的foreach解决了它,但我仍然对LINQ版本感兴趣。

5 个答案:

答案 0 :(得分:12)

这是一个完整的代码示例,应该适合您的情况。

class A
{
    public string Foo   { get; set; }
    public string Bar   { get; set; }
    public bool HasDupe { get; set; }
}

var list = new List<A> 
          { 
              new A{ Foo="abc", Bar="xyz"}, 
              new A{ Foo="def", Bar="ghi"}, 
              new A{ Foo="123", Bar="abc"}  
          };

var dupes = list.Where(a => list
          .Except(new List<A>{a})
          .Any(x => x.Foo == a.Foo || x.Bar == a.Bar || x.Foo == a.Bar || x.Bar == a.Foo))
          .ToList();

dupes.ForEach(a => a.HasDupe = true);

答案 1 :(得分:4)

这应该有效:

public class Foo
{
    public string Bar;
    public string Baz;
    public bool HasDuplicates;
}

public static void SetHasDuplicate(IEnumerable<Foo> foos)
{
    var dupes = foos
        .SelectMany(f => new[] { new { Foo = f, Str = f.Bar }, new { Foo = f, Str = f.Baz } })
        .Distinct() // Eliminates double entries where Foo.Bar == Foo.Baz
        .GroupBy(x => x.Str)
        .Where(g => g.Count() > 1)
        .SelectMany(g => g.Select(x => x.Foo))
        .Distinct()
        .ToList();

    dupes.ForEach(d => d.HasDuplicates = true);    
}

你基本上做的是

  1. SelectMany:创建所有字符串的列表及其随附的Foo
  2. 区别:删除同一个Foo实例的双重条目(Foo.Bar == Foo.Baz)
  3. GroupBy:按字符串分组
  4. 其中:过滤组中包含多个项目的组。这些包含重复项。
  5. SelectMany:从小组中取回foos。
  6. 区别:从列表中删除两次出现的foo。
  7. ForEach:设置HasDuplicates属性。
  8. 此解决方案优于Winston Smith解决方案的一些优点是:

    1. 更容易扩展到更多字符串属性。假设有5个属性。在他的解决方案中,您必须编写125个比较来检查重复项(在Any子句中)。在这个解决方案中,只需要在第一个selectmany调用中添加属性。
    2. 对于大型列表,性能应该更好。 Winston的解决方案迭代列表中每个项目的列表,而此解决方案只迭代一次。 (温斯顿的解是O(n²),而这个是O(n))。

答案 2 :(得分:0)

首先,如果您的对象尚未具有HasDuplicate属性,请声明一个实现HasDuplicateProperties的扩展方法:

public static bool HasDuplicateProperties<T>(this T instance)
    where T : SomeClass 
    // where is optional, but might be useful when you want to enforce
    // a base class/interface
{
    // use reflection or something else to determine wether this instance
    // has duplicate properties
    return false;
}

您可以在查询中使用该扩展方法:

var itemsWithDuplicates = from item in duplicationList
                          where item.HasDuplicateProperties()
                          select item;

与普通属性相同:

var itemsWithDuplicates = from item in duplicationList
                          where item.HasDuplicate
                          select item;

var itemsWithDuplicates = duplicationList.Where(x => x.HasDuplicateProperties());

答案 3 :(得分:0)

帽子提示https://stackoverflow.com/a/807816/492

var duplicates = duplicationList
                .GroupBy(l => l)
                .Where(g => g.Count() > 1)
                .Select(g => {foreach (var x in g)
                                 {x.HasDuplicate = true;}
                             return g;
                });

duplicates是一次性的,但它会以较少的枚举为您提供。

答案 4 :(得分:-1)

var dups = duplicationList.GroupBy(x => x).Where(y => y.Count() > 1).Select(y => y.Key);

foreach (var d in dups)
    Console.WriteLine(d);