【问题标题】:Finding Unique Objects between collections在集合之间查找唯一对象
【发布时间】:2021-09-24 09:14:54
【问题描述】:

我有一个测试,我创建了两个列表。一个代表我已经从某个来源(我无法控制)收集并收集的数据,另一个代表我的存储库中已经存在的已知数据。

它们看起来像这样:

var newAccounts = new[]
{
    new Account
    {
        Id = 1,
        SA_ID = 1,
        SA_Name = "Sa_Name1",
        RelationshipType = "new",
        LE_ID = 1,
        LE_GroupID = 1,
        SiteID = 1,
        MinDate = DateTime.Now.AddDays(-1),
        MaxDate = DateTime.Now.AddDays(1),
        DaysOn = 1,
        Child1 = new List<Child1>{ new Child1
            {
                SiteID = 1,
                MaxDate = DateTime.Today.AddDays(7),
                MinDate = DateTime.Today.AddDays(1),
            }
        },
        Child2 = new List<Child2>
        {
            new Child2
            {
                SA_ID = 1,
                LastUpdate = DateTime.Now.AddDays(-1),
                CommentText = "Account added",
                Status = AccountStatus.AccountAdded.ToString(),
            }
        }
    },
    new Account
    {
        Id = 2,
        SA_ID = 2,
        SA_Name = "Sa_Name2",
        RelationshipType = "new",
        LE_ID = 2,
        LE_GroupID = 2,
        SiteID = 2,
        MinDate = DateTime.Now.AddDays(-2),
        MaxDate = DateTime.Now.AddDays(2),
        DaysOn = 2,
    },
    new Account
    {
        Id = 3,
        SA_ID = 3,
        SA_Name = "Sa_Name3",
        RelationshipType = "new",
        LE_ID = 3,
        LE_GroupID = 3,
        SiteID = 3,
        MinDate = DateTime.Now.AddDays(-3),
        MaxDate = DateTime.Now.AddDays(3),
        DaysOn = 3,
    }
};

var knownAccounts = new[]
{
    new Account
    {
        Id = 1,
        SA_ID = 1,
        SA_Name = "Sa_Name1",
        RelationshipType = "new",
        LE_ID = 1,
        LE_GroupID = 1,
        SiteID = 1,
        MinDate = DateTime.Now.AddDays(-1),
        MaxDate = DateTime.Now.AddDays(1),
        DaysOn = 1,
        Child1 = new List<Child1>{ new Child1
            {
                SiteID = 1,
                MaxDate = DateTime.Today.AddDays(7),
                MinDate = DateTime.Today.AddDays(1),
            }
        },
        Child2 = new List<Child2>
        {
            new Child2
            {
                SA_ID = 1,
                LastUpdate = DateTime.Now.AddDays(-1),
                CommentText = "Account added",
                Status = AccountStatus.AccountAdded.ToString(),
            }
        }
    }
};

在我的单元测试中,我想从newAccounts 中删除Account ID 1,所以我的收藏中只剩下2 个条目。这些是我迄今为止的尝试:

public List<T> ReturnUniqueEntriesList<T>(List<T> newAccounts, List<T> knownAccounts)
{
    var a = knownAccounts.Intersect(newAccounts).ToList();

    var listA = newAccounts.Except(knownAccounts).ToList();
    var listB = knownAccounts.Except(newAccounts).ToList();

    var result = listB.Intersect(listA).ToList();

    return result;
}  

当我运行它时,最终结果为 0。a 也返回 0,listAlistB 只需返回它们各自的对象。

我在这里做错了什么/错过了什么?任何帮助将不胜感激

【问题讨论】:

  • 对于相交/排除等操作,列表中的对象需要具有可比性。如果不实现(IComparable、IEquatable 等)任何内容,将使用内存地址。所以 knownAccount 和 newAccount 中的实例总是不同的,因为它们是不同的实例,即使它们包含相同的数据。

标签: c# list linq collections


【解决方案1】:

为 Account 覆盖 Equals 和 GetHashcode,使它们不依赖于默认实现(对象的内存地址)。这意味着 C# 将能够在执行例外时正确地将它们等同起来。

例如:

public class Account{

    public override bool Equals(object other){
      return other is Account a && a.Id == this.Id; //nb; is returns false if other is a null, even if it is an Account
    }

    public override int GetHashCode(){
      return Id.GetHashCode();
    }
}

事实上,以下两个帐户非常不同:

var a = new Account { Id = 1 };
var b = new Account { Id = 1 };

..因为它们位于不同的内存地址。

通过重写 Equals 使其比较另一个的 Id,而不管其他属性,然后您基本上可以实现您似乎描述的“具有相同 ID 的两个帐户对象是等效的”的情况

如果其他属性因素影响决策,也添加这些属性。 Hashcode.Combine 是一种有用的方法,可以将多个哈希码组合起来,以解决获取多个属性的哈希码以产生合适的新信号哈希码的难题 - https://docs.microsoft.com/en-us/dotnet/api/system.hashcode.combine?view=net-5.0

【讨论】:

  • 是的,Enumerable.Except Method 的备注部分说 “默认相等比较器 Default,用于比较类型的值。要比较自定义数据类型,您需要覆盖Equals 和 GetHashCode 方法,并可选择在自定义类型中实现 IEquatable 泛型接口。".
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-01
  • 2020-05-13
  • 1970-01-01
  • 2020-08-25
  • 2020-12-19
相关资源
最近更新 更多