【问题标题】:remove duplicate from list in object c#从对象c#中的列表中删除重复项
【发布时间】:2020-02-09 19:18:43
【问题描述】:

我正在拼命尝试删除所有具有相同值列表的项目。

代码如下:

    private void Button_deleteDouble_MouseDown(object sender, EventArgs e)
    {
        boardGenerate.Add(new BoardInformation(146, new List<string> { "test" }));
        boardGenerate.Add(new BoardInformation(545, new List<string> { "test" }));

        boardGenerate = boardGenerate.DistinctBy(x => x.positionQueen).ToList();
    }

通常,由于对象内的两个列表是相同的,因此 .DistinctBy() 命令应该删除两个对象之一。

但是不,我的对象列表仍然有相同列表的两个对象

.positionQueen 是包含列表的变量的名称

有人可以帮我吗?

编辑:

DistinctBy()方法来自MoreLinq

这是我的 BoardInformation 类:

public class BoardInformation
{
    public BoardInformation(int nbQueen, List<string> positionQueen)
    {
        this.nbQueen = nbQueen;
        this.positionQueen = positionQueen;
    }

    public int nbQueen { get; set; }
    public List<string> positionQueen { get; set; }     
}

【问题讨论】:

  • 我们对BoardInformation一无所知也无济于事。请提供minimal reproducible example。但请注意List&lt;T&gt; 不会覆盖EqualsGetHashCode。如果positionQueenList&lt;string&gt;,您可能需要为DistinctBy 调用提供IEqualityComparer&lt;List&lt;string&gt;&gt;。 (如果你能说出这是哪个DistinctBy 方法也会有所帮助 - 是 MoreLINQ 吗?)
  • 我进行了编辑。我完全不明白你所说的 Equal 和 GetHashCode 是什么意思,你能解释一下吗?
  • 你添加了2个东西,然后用Distinct选择,为什么会删除?
  • 您有两个列表。它们具有相同的内容,但尝试打印出boardGenerate[0].positionQueen.Equals(boardGenerate[1].positionQueen),它会打印出False,因为List&lt;T&gt; 不会覆盖Equals - 这就是DistinctBy 用来查找相等值的原因。
  • 顺便说一句,我强烈建议您开始关注.NET naming conventions

标签: c# distinct


【解决方案1】:

DistinctDistinctBy 这样的基于集合的操作需要一种方法来确定两个值是否相同。您正在使用 DistinctBy,因此您已经在要求 MoreLINQ 比较“内部列表”是否相等 - 但您并没有说明如何做到这一点。

List&lt;T&gt; 不会覆盖EqualsGetHashCode,这意味着它从System.Object 继承引用相等 行为。换句话说,如果您创建两个单独的List&lt;T&gt; 对象,即使它们具有相同的内容,它们也不会相等。例如:

List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
Console.WriteLine(list1.Equals(list2)); // False

您需要告诉DistinctBy 您想如何比较两个列表,使用IEqualityComparer&lt;T&gt; - 在这种情况下TList&lt;string&gt;(因为这是BoardInformation.positionQueen 的类型。

这是您可以使用的通用 ListEqualityComparer 示例:

using System;
using System.Collections.Generic;
using System.Linq;

public sealed class ListEqualityComparer<T> : IEqualityComparer<List<T>>
{
    private readonly IEqualityComparer<T> elementComparer;

    public ListEqualityComparer(IEqualityComparer<T> elementComparer) =>
        this.elementComparer = elementComparer;

    public ListEqualityComparer() : this(EqualityComparer<T>.Default)
    {
    }

    public bool Equals(List<T> x, List<T> y) =>
        ReferenceEquals(x, y) ? true
        : x is null || y is null ? false
        // Delegate to LINQ's SequenceEqual method
        : x.SequenceEqual(y, elementComparer);

    public int GetHashCode(List<T> obj)
    {
        if (obj is null)
        {
            return 0;
        }
        // Just a very simple hash implementation
        int hash = 23;
        foreach (var item in obj)
        {
            hash = hash * 31 +
                (item is null ? 0
                 : elementComparer.GetHashCode(item));
        }
        return hash;
    }
}

然后您将其传递给DistinctBy,如下所示:

// We're fine to use the default *element* comparer (string.Equals etc)
var comparer = new ListEqualityComparer<string>();
boardGenerate = boardGenerate.DistinctBy(x => x.positionQueen, comparer).ToList();

现在DistinctBy 将调用比较器,传入列表,并认为你的两个BoardInformation 对象是相等的 - 所以只有第一个对象会被DistinctBy 产生,你最终会得到一个包含单个项目的列表。

【讨论】:

    【解决方案2】:

    归结为相等检查是使用引用相等还是值相等...您希望基于特定属性的值相等并且必须手动完成。

    当没有提供IEqualityComparer 可用于比较单个对象时(Distinct 调用需要),系统根据每个项目的引用确定相等性 使用它们从每个引用中派生的object 低级服务方法调用GetHashCode;因此,参考差异已完成,并且列表中的所有值都是唯一的(不等于),无论是否具有相似的属性值。

    您正在寻找的是专门为nbQueenProperty 检查值相等


    要充分利用Distinct,必须创建IEqualityComparer 并修改GetHashCode。通过指定可以使对象相等的哈希值...您可以清除相同的positionQueen或其他属性)实例。

    示例

    public class MyClass
    {
        public string Name { get; set; }
        public int nbQueen { get; set; }
    }
    

    消除所有 nbQueen 相似之处的平等比较器:

    class ContactEmailComparer : IEqualityComparer < MyClass >
    {
        public bool Equals(MyClass x, MyClass y)
        {
          return x.nbQueen.Equals(y.nbQueen); // Compares by calling each `GetHashCode` 
        }
    
        public int GetHashCode(MyClass obj)
        {
            return obj.nbQueen.GetHashCode(); // Add or remove other properties as needed.
        }
    }
    

    测试代码

    var original = new List<MyClass>()
    {
        new MyClass() { nbQueen = 1, Name="Alpha"   },
        new MyClass() { nbQueen = 1, Name="Omega" },
        new MyClass() { nbQueen = 3, Name="Delta" }
    
    };
    
    IEqualityComparer<MyClass> comparer = new ContactEmailComparer();
    
    var newOne = original.Distinct( comparer ).ToList();
    

    newOne 值的结果:


    说清楚……

    ... .DistinctBy() 命令应该删除两个对象之一。

    不删除任何内容。它返回一个对新列表的引用,该列表应该通过相等操作来区分。原始列表(对它的引用)没有改变。

    【讨论】:

    • “它通过引用值进行比较” - 好吧,它调用 Equals/GetHashCode,默认情况下使用引用标识来表示相等。但如果类型本身覆盖了 Equals/GetHashCode,那就另当别论了。我认为第一段可以澄清。
    • @JonSkeet 够公平的。更新了第一部分,以区分默认执行的引用相等操作(使用 GetHashCode 关闭 Object)与用户期望的感知 值相等
    • 它使用EqualsGetHashCode - 不使用Equals 的实现是不正确的。我不得不说,如果我还不知道发生了什么,我会发现很难理解你的解释 - 特别是,你似乎 假设 OP 希望在条款上平等nbQueen,但没有迹象表明这是他们真正想要做的。事实上,他们明确表示他们想比较这些列表。如果 OP 真的只想通过 nbQueen 进行比较,他们可以使用 boardGenerate.DistinctBy(x =&gt; x.nbQueen) - 根本不涉及自定义比较器。
    • 至少我已经给了 OP 一份关于如何使用 Distinct 的指南……希望能在短期内回答这个问题。我基于 OP 的请求,提到 OP 声称的 boardGenerate = boardGenerate.DistinctBy(x =&gt; x.positionQueen).ToList(); 不起作用(对于这种情况?):“但是不,我的对象列表仍然具有相同列表的相同两个对象”
    • 是的,它不起作用因为List&lt;T&gt; 默认使用引用相等。提供IEqualityComparer&lt;List&lt;T&gt;&gt; 作为DistinctBy 的第二个参数可以正常工作。我不明白你为什么会认为 OP 使用了完全错误的属性。他们给出的示例甚至没有对两个值使用相同的 nbQueen 值,因此您的代码将给出相同的结果(当 OP 希望将它们视为相等时,考虑到这两个对象不相等)。
    【解决方案3】:

    LINQ 解决方案

    因为您的班级中有另一个列表,所以您不能使用 District 或 DistrictBy,或者,您可以使用 LINQ 过滤列表。

         boardGenerate = (from b in boardGenerate
                          from l in b.positionQueen
                          group new { l,b } by l into g
                          select g.First().b
                          ).ToList();
       // this returns just first duplicate item like district
    
    

    【讨论】:

      猜你喜欢
      • 2017-06-23
      • 2021-12-11
      • 2018-07-19
      • 2012-01-09
      • 1970-01-01
      • 2022-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多