【问题标题】:Group and delete repeated data in lists c #对列表中的重复数据进行分组和删除c#
【发布时间】:2019-08-20 11:28:12
【问题描述】:

我想知道如何实现分组和消除重复数据,例如我有这个类:

public class MyObject
{
    public string attrb1{ get; set; }
    public string attrb2{ get; set; }
}

我想“调试”重复的对象,尝试以下方法,但它不起作用。

List<MyObject> ListObject = new List<MyObject>();

var obj1 = new MyObject{attrb1="attrb1", attrb2="attrb2"}
ListObject.Add(obj1);

var obj2 = new MyObject{attrb1="attrb1", attrb2="attrb2"}
ListObject.Add(obj2);


List<MyObject> GroupedList= new List<MyObject>();

foreach(var obj in ListObject)
{
    if(!GroupedList.Contains(obj))
        GroupedList.Add(obj);
}

【问题讨论】:

  • 在这种情况下比较引用实例,您需要实现IEquatable或您自己的相等比较器。
  • 在您的代码中GroupedList 为空,因此ListaObjetos 中的所有项目都添加到GroupedList
  • obj1 和 obj2 是两个不同的实例,虽然它们的属性是相等的
  • 考虑哈希集?

标签: c# list


【解决方案1】:

最好的解决方案是使用Enumerable.Union,它将返回一个新列表,其中包含两个集合的union。为此,我们需要覆盖 Object.Equals 以确保只比较属性而不比较引用

为方便起见,我们将使用IEquatable&lt;T&gt;

/// <summary>
/// Inherit from interface <see cref="IEquatable{T}"/>
/// </summary>
public class Objeto : IEquatable<Objeto>
{
    public string atributo1 { get; set; }
    public string atributo2 { get; set; }

    /// <summary>
    /// Implements <see cref="Equals(Objeto)"/> method from interface <see cref="IEquatable{T}"/>
    /// </summary>
    /// <param name="other">The second object we will compare.</param>
    /// <returns></returns>
    public bool Equals(Objeto other)
    {
        //If the object is null, are not equal.
        if(other==null)return false;
        //If isn't null we compare both attributes.
        return atributo1==other.atributo1&&atributo2==other.atributo2;
    }

    //Override Equals calling the Equals(Object) implementation.
    public override bool Equals(object obj) => Equals(obj as Objeto);

    //override GetHashCode making sure that if Equals is true, both objects must have the same HashCode.
    public override int GetHashCode()
    {
        return atributo1.GetHashCode() ^ atributo2.GetHashCode();
    }
}

现在,我们可以将Enumerable.UnionObjeto 类型的对象一起使用

List<Objeto> list1 = new List<Objeto>{new Objeto{atributo1="Dato1", atributo2 = "Dato2"}};
List<Objeto> list2 = new List<Objeto>
{
    new Objeto{atributo1="Dato1", atributo2 = "Dato2"},
    new Objeto{atributo1="Dato3", atributo2 = "Dato4"}
};

//Get the unión between both lists
var listaDefinitiva = list1.Union(list2);

foreach (var objeto in listaDefinitiva)
{
    Console.WriteLine("Atributo1: {0}\t Atributo2: {1}",objeto.atributo1,objeto.atributo2);
}

控制台输出将是

Atributo1: Dato1         Atributo2: Dato2
Atributo1: Dato3         Atributo2: Dato4

【讨论】:

    【解决方案2】:

    您正在寻找的是.Distinct()。要将其用于自定义对象,您首先需要定义 一个EqualityComparer,像这样:

    public class MyObjectComparer : EqualityComparer<MyObject>
    {
        public override bool Equals(MyObject x, MyObject y)
        {
            return x.attrb1 == y.attrb1 && x.attrb2 == y.attrb2;
        }
    
        public override int GetHashCode(MyObject obj)
        {
            return (obj.attrb1 + obj.attrb2).GetHashCode();
        }
    }
    

    然后您可以将其用作(从而完全消除 for 循环):

    var distinct = ListObject.Distinct(new MyObjectComparer());
    

    【讨论】:

      【解决方案3】:

      默认情况下,类之间的相等性是通过比较它们的引用(内存位置)来确定的,因此两个类只有在它们都指向同一个实例时才相等。

      如果您想定义一种不同的确定相等性的方法,那么您需要覆盖Equals 方法(和GetHashCode)。

      如果两个 MyObject 实例的 attrib1 属性相等且它们的 attrib2 属性相等,则您似乎希望将两个 MyObject 实例视为相等。如果是这种情况,您可以像这样覆盖Equals

      public class MyObject
      {
          public string attrb1 { get; set; }
          public string attrb2 { get; set; }
      
          public override bool Equals(object obj)
          {
              var other = obj as MyObject;
              return other != null && other.attrb1 == attrb1 && other.attrb2 == attrb2;
          }
      
          public override int GetHashCode()
          {
              return (attrb1 + attrb2).GetHashCode();
          }
      }
      

      进行此更改后,您的示例代码中的GroupedList 将只包含一项。

      【讨论】:

        【解决方案4】:

        您可能想查看this link, 尤其是以下示例:

        int[] ints1 = { 5, 3, 9, 7, 5, 9, 3, 7 };
        int[] ints2 = { 8, 3, 6, 4, 4, 9, 1, 0 };
        
        IEnumerable<int> union = ints1.Union(ints2);
        

        还有这个

        List<int> ages = new List<int> { 21, 46, 46, 55, 17, 21, 55, 55 };
        
        IEnumerable<int> distinctAges = ages.Distinct();
        

        只要确保您正在导入 System.Linq

        using System.Linq
        

        【讨论】:

        • 但是 UnionDistinct 不能像 OP 所希望的那样与 MyObject 一起使用,因为它们使用 Equals 方法来确定相等性......
        • 他们不必使用它。我在他们的代码中没有看到。他们可以按照其他答案的建议编写比较器。但是,如果您想从集合中选择唯一值“消除重复数据”,则使用 Distinct 或 Union 是一种方法。
        • 我的意思是这个答案似乎暗示他们将示例代码修改为:IEnumerable&lt;MyObject&gt; GroupedList = ListObject.Distinct();,我是说如果不覆盖 Equals 或编写比较器,这将无法按预期工作.
        猜你喜欢
        • 1970-01-01
        • 2020-01-13
        • 2020-01-23
        • 1970-01-01
        • 1970-01-01
        • 2016-08-29
        • 2014-05-09
        • 1970-01-01
        • 2023-03-07
        相关资源
        最近更新 更多