我可以使用LINQ来比较两个集合之间缺少、添加或更新的内容吗

本文关键字:添加 更新 之间 集合 LINQ 可以使 比较 两个 我可以 | 更新日期: 2023-09-27 18:27:03

我有以下类。为了进行比较,我添加了一个Equals方法:

 public ObjectiveDetail()
    public int ObjectiveDetailId { get; set; }
    public int Number { get; set; }
    public string Text { get; set; }
    public override bool Equals(object obj)
    {
        return this.Equals(obj as ObjectiveDetail);
    }
    public bool Equals(ObjectiveDetail other)
    {
        if (other == null)
            return false;
        return this.Number.Equals(other.Number) &&
            (
                this.Text == other.Text ||
                this.Text != null &&
                this.Text.Equals(other.Text)
            );
    }
 }

我有两个ICollection集合:

ICollection<ObjectiveDetail> _obj1; // Reference
ICollection<ObjectiveDetail> _obj2; // May have more, less or different objectDetails from the reference.

集合的公共tfield是ObjectiveDetailId。有没有一种方法可以使用三个LINQ表达式来创建:

  • _obj2而非_obj1中的行的集合
  • _obj1而非_obj2中的行的集合
  • _obj1和_obj2之间不同的行的集合

注意,这与我之前问的另一个问题类似,但我认为现在我添加了Equals方法,这会简单一些。可以这样做吗?

我可以使用LINQ来比较两个集合之间缺少、添加或更新的内容吗

您可以使用Except减去集合:

var in2butNot1 = _obj2.Except(_obj1);
var in1butNot2 = _obj1.Except(_obj2);

然而,这可能不是你想要得到的,因为已经"改变"的对象将被视为彼此"不平等"。

您的对象似乎有一个ID字段。您可以对ID上的对象进行排序,然后遍历这两个集合,就像生成合并一样。这将使您能够使用直接的if s链来检测插入、更新和删除。

您还可以使用ID来决定什么是常见的以及发生了什么变化:

var ids1 = new HashSet<int>(_obj1.Select(o => o.ObjectiveDetailId));
var ids2 = new HashSet<int>(_obj2.Select(o => o.ObjectiveDetailId));
var in2butNot1 = _obj2.Where(o => !ids1.Contains(o.ObjectiveDetailId));
var in1butNot2 = _obj1.Where(o => !ids2.Contains(o.ObjectiveDetailId));

您应该始终覆盖EqualsGetHashCode:

  • _obj2而非_obj1 中的行集合

    var inObj2NotInObj1 = _obj2.Except(_obj1).ToList();
    
  • _obj1而非_obj2 中的行集合

    var inObj1NotInObj2 = _obj1.Except(_obj2).ToList();
    
  • _obj1和_obj2 之间不同的行的集合

指定不同的,如果你的意思不是Equals,那就是你上面所说的。

我对not Equals的意思是当对象具有相同的ObjectiveDetailId,但不同的"Number"或"Text"字段值。

如果你创建了一个将ID映射到原始(_obj1)对象的字典,那么你可以为每个新(_obj2)对象查找具有匹配ID的原始对象,并比较:

var oldDictionary = _obj1.ToDictionary(old => old.ObjectiveDetailId);
var updated = _obj2.Where(current => {
    ObjectiveDetail old = null;
    var isExisting = oldDictionary.TryGetValue(current.ObjectiveDetailId, out old);
    return isExisting && !old.Equals(current);
});