【问题标题】:Remove duplicates in the list using linq使用 linq 删除列表中的重复项
【发布时间】:2009-10-22 11:48:26
【问题描述】:

我有一个Itemsproperties (Id, Name, Code, Price) 的课程。

Items 的列表中填充了重复项。

例如:

1         Item1       IT00001        $100
2         Item2       IT00002        $200
3         Item3       IT00003        $150
1         Item1       IT00001        $100
3         Item3       IT00003        $150

如何使用 linq 删除列表中的重复项?

【问题讨论】:

  • 我在 Items 类中还有另一个类作为属性
  • 你也可以var set = new HashSet<int>(); var uniques = items.Where(x => set.Add(x.Id));。这样做应该是犯罪行为..

标签: c# linq linq-to-objects generic-list


【解决方案1】:
var distinctItems = items.GroupBy(x => x.Id).Select(y => y.First());

【讨论】:

  • 谢谢 - 想避免写一个比较器类,所以我很高兴这个工作:)
  • +1 这个解决方案甚至允许决胜局:使用标准消除重复!
  • 不过有点开销!
  • 但是,正如 Victor Juri 下面建议的那样:使用 FirstorDefault。不敢相信,这个解决方案可以这么简单(没有自定义相等比较器)
  • 您可以使用多个属性进行分组: List MyUniqueList = MyList.GroupBy(x => new { x.Column1, x.Column2 }).Select(g=> g.First() ).ToList();
【解决方案2】:
var distinctItems = items.Distinct();

要仅匹配某些属性,请创建自定义相等比较器,例如:

class DistinctItemComparer : IEqualityComparer<Item> {

    public bool Equals(Item x, Item y) {
        return x.Id == y.Id &&
            x.Name == y.Name &&
            x.Code == y.Code &&
            x.Price == y.Price;
    }

    public int GetHashCode(Item obj) {
        return obj.Id.GetHashCode() ^
            obj.Name.GetHashCode() ^
            obj.Code.GetHashCode() ^
            obj.Price.GetHashCode();
    }
}

然后像这样使用它:

var distinctItems = items.Distinct(new DistinctItemComparer());

【讨论】:

  • 嗨 Christian,如果我有一个 List 和 List,代码会有什么变化。我的自定义类有各种项目,其中一项是 DCN 编号,而 list 只有 DCN 编号。所以我需要检查 List 是否包含来自 List 的任何 dcn。例如,假设 List1 = List 和 List2 = List。如果 List1 有 2000 个项目,而 list2 有 40000 个项目,则 List1 中的 600 个项目存在于 List2 中。所以在这种情况下,我需要 1400 作为我的输出列表作为 list1。那会是什么表情。提前致谢
  • 这里还有一种情况,因为 List1 包含各种项目,其他项目值可能不同但 DCN 必须相同。所以在我的情况下,Distinct 未能提供理想的输出。
  • 我发现比较器类非常有用。它们可以表达除了简单的属性名称比较之外的逻辑。上个月我写了一个新的,做一些GroupBy 做不到的事情。
  • 效果很好,让我学到了一些新东西,并研究了 C# 中的 XoR 运算符 ^。曾通过Xor 在 VB.NET 中使用过,但必须对您的代码进行双重检查才能看到它最初是什么。
  • 这是我尝试使用 Distinct Comparer 时遇到的错误:“LINQ to Entities 无法识别方法 'System.Linq.IQueryable1[DataAccess.HR.Dao.CCS_LOCATION_TBL] Distinct[CCS_LOCATION_TBL](System.Linq.IQueryable1[DataAccess.HR.Dao.CCS_LOCATION_TBL] , System.Collections.Generic.IEqualityComparer`1[DataAccess.HR.Dao.CCS_LOCATION_TBL])' 方法,并且该方法不能翻译成商店表达式。
【解决方案3】:

如果您的 Distinct 查询有问题,您可能需要查看 MoreLinq 并使用 DistinctBy 运算符并按 id 选择不同的对象。

var distinct = items.DistinctBy( i => i.Id );

【讨论】:

  • Linq 没有 DistinctBy() 方法。
  • @FereydoonBarikzehy 但他不是在谈论纯 Linq。在帖子中是 linq to MoreLinq 项目...
【解决方案4】:

这就是我能够与 Linq 进行分组的方式。希望对您有所帮助。

var query = collection.GroupBy(x => x.title).Select(y => y.FirstOrDefault());

【讨论】:

  • @nawfal,我建议用 FirstOrDefault() 代替 First()
  • 如果我是正确的,如果Select 紧跟在GroupBy 之后,则在此处使用FirstOrDefault 没有任何好处,因为不可能有一个空组(这些组只是源自集合的内容)
【解决方案5】:

一种通用的扩展方法:

public static class EnumerableExtensions
{
    public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> keySelector)
    {
        return enumerable.GroupBy(keySelector).Select(grp => grp.First());
    }
}

使用示例:

var lstDst = lst.DistinctBy(item => item.Key);

【讨论】:

  • 非常干净的方法
  • 谢谢,这正是我想要的,效果很好。
【解决方案6】:

您可以在这里使用三个选项来删除列表中的重复项:

  1. 使用自定义的相等比较器,然后使用 Distinct(new DistinctItemComparer()),正如提到的 @Christian Hayter
  2. 使用GroupBy,但请注意在GroupBy 中您应该按所有列分组,因为如果您只是按Id 分组,它不会始终删除重复项。例如考虑以下示例:

    List<Item> a = new List<Item>
    {
        new Item {Id = 1, Name = "Item1", Code = "IT00001", Price = 100},
        new Item {Id = 2, Name = "Item2", Code = "IT00002", Price = 200},
        new Item {Id = 3, Name = "Item3", Code = "IT00003", Price = 150},
        new Item {Id = 1, Name = "Item1", Code = "IT00001", Price = 100},
        new Item {Id = 3, Name = "Item3", Code = "IT00003", Price = 150},
        new Item {Id = 3, Name = "Item3", Code = "IT00004", Price = 250}
    };
    var distinctItems = a.GroupBy(x => x.Id).Select(y => y.First());
    

    此分组的结果将是:

    {Id = 1, Name = "Item1", Code = "IT00001", Price = 100}
    {Id = 2, Name = "Item2", Code = "IT00002", Price = 200}
    {Id = 3, Name = "Item3", Code = "IT00003", Price = 150}
    

    这是不正确的,因为它将{Id = 3, Name = "Item3", Code = "IT00004", Price = 250} 视为重复。所以正确的查询是:

    var distinctItems = a.GroupBy(c => new { c.Id , c.Name , c.Code , c.Price})
                         .Select(c => c.First()).ToList();
    

    3.在项目类中覆盖EqualGetHashCode

    public class Item
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Code { get; set; }
        public int Price { get; set; }
    
        public override bool Equals(object obj)
        {
            if (!(obj is Item))
                return false;
            Item p = (Item)obj;
            return (p.Id == Id && p.Name == Name && p.Code == Code && p.Price == Price);
        }
        public override int GetHashCode()
        {
            return String.Format("{0}|{1}|{2}|{3}", Id, Name, Code, Price).GetHashCode();
        }
    }
    

    那么你可以这样使用它:

    var distinctItems = a.Distinct();
    

【讨论】:

    【解决方案7】:

    使用Distinct(),但请记住它使用默认的相等比较器来比较值,因此如果您想要除此之外的任何内容,则需要实现自己的比较器。

    请参阅http://msdn.microsoft.com/en-us/library/bb348436.aspx 获取示例。

    【讨论】:

    • 我应该注意到,如果集合成员类型是值类型之一,则默认比较器可以工作。但是 csc 为引用类型选择哪个默认相等比较器。引用类型必须有自己的比较器。
    【解决方案8】:

    试试这个扩展方法。希望这会有所帮助。

    public static class DistinctHelper
    {
        public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            var identifiedKeys = new HashSet<TKey>();
            return source.Where(element => identifiedKeys.Add(keySelector(element)));
        }
    }
    

    用法:

    var outputList = sourceList.DistinctBy(x => x.TargetProperty);
    

    【讨论】:

      【解决方案9】:
      List<Employee> employees = new List<Employee>()
      {
          new Employee{Id =1,Name="AAAAA"}
          , new Employee{Id =2,Name="BBBBB"}
          , new Employee{Id =3,Name="AAAAA"}
          , new Employee{Id =4,Name="CCCCC"}
          , new Employee{Id =5,Name="AAAAA"}
      };
      
      List<Employee> duplicateEmployees = employees.Except(employees.GroupBy(i => i.Name)
                                                   .Select(ss => ss.FirstOrDefault()))
                                                  .ToList();
      

      【讨论】:

        【解决方案10】:

        另一种解决方法,不美观购买可行。

        我有一个 XML 文件,其中包含一个名为“MEMDES”的元素,它具有两个属性“GRADE”和“SPD”来记录 RAM 模块信息。 SPD中有很多重复项。

        所以这是我用来删除重复项的代码:

                IEnumerable<XElement> MList =
                    from RAMList in PREF.Descendants("MEMDES")
                    where (string)RAMList.Attribute("GRADE") == "DDR4"
                    select RAMList;
        
                List<string> sellist = new List<string>();
        
                foreach (var MEMList in MList)
                {
                    sellist.Add((string)MEMList.Attribute("SPD").Value);
                }
        
                foreach (string slist in sellist.Distinct())
                {
                    comboBox1.Items.Add(slist);
                }
        

        【讨论】:

          【解决方案11】:

          当您不想编写 IEqualityComparer 时,可以尝试以下操作。

           class Program
          {
          
              private static void Main(string[] args)
              {
          
                  var items = new List<Item>();
                  items.Add(new Item {Id = 1, Name = "Item1"});
                  items.Add(new Item {Id = 2, Name = "Item2"});
                  items.Add(new Item {Id = 3, Name = "Item3"});
          
                  //Duplicate item
                  items.Add(new Item {Id = 4, Name = "Item4"});
                  //Duplicate item
                  items.Add(new Item {Id = 2, Name = "Item2"});
          
                  items.Add(new Item {Id = 3, Name = "Item3"});
          
                  var res = items.Select(i => new {i.Id, i.Name})
                      .Distinct().Select(x => new Item {Id = x.Id, Name = x.Name}).ToList();
          
                  // now res contains distinct records
              }
          
          
          
          }
          
          
          public class Item
          {
              public int Id { get; set; }
          
              public string Name { get; set; }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-11-28
            • 1970-01-01
            相关资源
            最近更新 更多