C# 比较两个类似于Diff工具的类对象列表

C# 比较两个类似于Diff工具的类对象列表,c#,linq,diff,iequalitycomparer,compareobject,C#,Linq,Diff,Iequalitycomparer,Compareobject,问题已提出 我的要求是编写一个类似于diff工具的程序。是的,有相当多的库和开源代码实现了这一目的,但我想编写自己的比较器 这是起点。我有一个名为DataItem的类,它如下所示: public class DataItem { public DataItem() { } public DataItem(string d, string v) { Data = d; Value = v; } public string Data { get; set; } pu

问题已提出

我的要求是编写一个类似于diff工具的程序。是的,有相当多的库和开源代码实现了这一目的,但我想编写自己的比较器

这是起点。我有一个名为DataItem的类,它如下所示:

public class DataItem
{
    public DataItem() { }
    public DataItem(string d, string v) { Data = d; Value = v; }

    public string Data { get; set; }
    public string Value { get; set; }
}
Added Items:
EEE,9

Removed Items:
CCC,3
GGG,3

Diff Items:
BBB
FFF
public class DiffItem
{
    public DiffItem() { }
    public DiffItem(string data, string type, string pre, string post) { Data = data; DiffType = type; PreVal = pre; PostVal = post; }

    public string Data { get; set; }
    public string DiffType { get; set; } // DiffType = Add/Remove/Diff
    public string PreVal { get; set; } // preList value corresponding to Data item
    public string PostVal { get; set; } // postList value corresponding to Data item
}
我有两个这些类对象的列表,让我们称它们为PRE和POST,并取一些示例值,如下所示数据的部分在列表中是唯一的

preList: (Data,Value)
AAA,0
BBB,1
CCC,3
DDD,4
FFF,0
GGG,3

postList: (Data,Value)
AAA,0
BBB,2
DDD,4
EEE,9
FFF,3
将PRE视为原始列表,并在完成一些更改后将POST视为列表。我想将两者进行比较,并将其分为三类:

  • 添加的项目-列表中添加了新“数据”的项目
  • 已删除项目-已从列表中删除项目
  • Diff Items—“Data”在PRE和POST列表中都可以找到,但它们对应的“Value”是不同的
  • 因此,分类时,它们应该如下所示:

    public class DataItem
    {
        public DataItem() { }
        public DataItem(string d, string v) { Data = d; Value = v; }
    
        public string Data { get; set; }
        public string Value { get; set; }
    }
    
    Added Items:
    EEE,9
    
    Removed Items:
    CCC,3
    GGG,3
    
    Diff Items:
    BBB
    FFF
    
    public class DiffItem
    {
        public DiffItem() { }
        public DiffItem(string data, string type, string pre, string post) { Data = data; DiffType = type; PreVal = pre; PostVal = post; }
    
        public string Data { get; set; }
        public string DiffType { get; set; } // DiffType = Add/Remove/Diff
        public string PreVal { get; set; } // preList value corresponding to Data item
        public string PostVal { get; set; } // postList value corresponding to Data item
    }
    
    我还有另一个DiffItem类,我想把最终结果放在它的对象上。DiffItem如下所示:

    public class DataItem
    {
        public DataItem() { }
        public DataItem(string d, string v) { Data = d; Value = v; }
    
        public string Data { get; set; }
        public string Value { get; set; }
    }
    
    Added Items:
    EEE,9
    
    Removed Items:
    CCC,3
    GGG,3
    
    Diff Items:
    BBB
    FFF
    
    public class DiffItem
    {
        public DiffItem() { }
        public DiffItem(string data, string type, string pre, string post) { Data = data; DiffType = type; PreVal = pre; PostVal = post; }
    
        public string Data { get; set; }
        public string DiffType { get; set; } // DiffType = Add/Remove/Diff
        public string PreVal { get; set; } // preList value corresponding to Data item
        public string PostVal { get; set; } // postList value corresponding to Data item
    }
    
    为了实现这一点,我首先扩展了IEqualityComparer并编写了两个比较器:

    public class DataItemComparer : IEqualityComparer<DataItem>
    {
        public bool Equals(DataItem x, DataItem y)
        {
            return (string.Equals(x.Data, y.Data) && string.Equals(x.Value, y.Value));
        }
    
        public int GetHashCode(DataItem obj)
        {
            return obj.Data.GetHashCode();
        }
    }
    
    public class DataItemDataComparer : IEqualityComparer<DataItem>
    {
        public bool Equals(DataItem x, DataItem y)
        {
            return string.Equals(x.Data, y.Data);
        }
    
        public int GetHashCode(DataItem obj)
        {
            return obj.Data.GetHashCode();
        }
    }
    
    公共类DataItemComparer:IEqualityComparer
    {
    公共布尔等于(数据项x、数据项y)
    {
    返回(string.Equals(x.Data,y.Data)&&string.Equals(x.Value,y.Value));
    }
    public int GetHashCode(DataItem obj)
    {
    返回obj.Data.GetHashCode();
    }
    }
    公共类DataItemDataComparer:IEqualityComparer
    {
    公共布尔等于(数据项x、数据项y)
    {
    返回字符串.Equals(x.Data,y.Data);
    }
    public int GetHashCode(DataItem obj)
    {
    返回obj.Data.GetHashCode();
    }
    }
    
    然后使用Except()和Intersect()方法,如下所示:

        static void DoDiff()
        {
            diffList = new List<DiffItem>();
    
            IEnumerable<DataItem> preOnly = preList.Except(postList, new DataItemComparer());
            IEnumerable<DataItem> postOnly = postList.Except(preList, new DataItemComparer());
            IEnumerable<DataItem> common = postList.Intersect(preList, new DataItemComparer());
    
            IEnumerable<DataItem> added = postOnly.Except(preOnly, new DataItemDataComparer());
            IEnumerable<DataItem> removed = preOnly.Except(postOnly, new DataItemDataComparer());
            IEnumerable<DataItem> diffPre = preOnly.Intersect(postOnly, new DataItemDataComparer());
            IEnumerable<DataItem> diffPost = postOnly.Intersect(preOnly, new DataItemDataComparer());
    
            foreach (DataItem add in added)
            {
                diffList.Add(new DiffItem(add.Data, "Add", null, add.Value));
            }
            foreach (DataItem rem in removed)
            {
                diffList.Add(new DiffItem(rem.Data, "Remove", rem.Value, null));
            }
            foreach (DataItem pre in diffPre)
            {
                DataItem post = diffPost.First(x => x.Data == pre.Data);
                diffList.Add(new DiffItem(pre.Data, "Diff", pre.Value, post.Value));
            }
        }
    
    static void DoDiff()
    {
    diffList=新列表();
    IEnumerable preOnly=preList.Except(postList,new DataItemComparer());
    IEnumerable postOnly=postList.Except(preList,new DataItemComparer());
    IEnumerable common=postList.Intersect(预列表,新的DataItemComparer());
    IEnumerable added=postOnly.Except(仅限新的DataItemDataComparer());
    IEnumerable removed=preOnly.Except(postOnly,new DataItemDataComparer());
    IEnumerable diffPre=preOnly.Intersect(postOnly,new DataItemDataComparer());
    IEnumerable diffPost=postOnly.Intersect(仅限新的DataItemDataComparer());
    foreach(已添加DataItem外接程序)
    {
    Add(新的DiffItem(Add.Data,“Add”,null,Add.Value));
    }
    foreach(删除数据项rem)
    {
    添加(新的DiffItem(rem.Data,“Remove”,rem.Value,null));
    }
    foreach(diffPre中的DataItem pre)
    {
    DataItem post=diffPost.First(x=>x.Data==pre.Data);
    添加(新的DiffItem(pre.Data,“Diff”、pre.Value、post.Value));
    }
    }
    
    这确实有效,并且完成了工作。但我想知道是否有更好的方法来做到这一点。请注意,我在“更好”一词周围加了引号,因为我没有一个合适的定义来说明什么能让它更好。也许有一种方法可以在不使用那么多“foreach”循环和使用Except()和Intersetc()的情况下完成这项工作,因为我可以想象在Linq后面有相当多的迭代正在进行


    简单地说,是否有一个更干净的代码,我可以写这个?我的提问主要是出于学术兴趣和扩大我的知识面。

    我认为您不需要您的IEQuality Comparer:

    var added = from a in postList
                where !preList.Any(b => b.Data == a.Data)
                select new DiffItem(a.Data, "Add", null, a.Value);
    var removed = from b in preList
                  where !postList.Any(a => a.Data == b.Data)
                  select new DiffItem(b.Data, "Remove", b.Value, null);
    var diff = from b in preList
               join a in postList on b.Data equals a.Data
               where b.Value != a.Value
               select new DiffItem(b.Data, "Diff", b.Data, a.Data);
    var diffList = added.ToList();
    diffList.AddRange(removed);
    diffList.AddRange(diff);
    

    这将是更好地张贴到。谢谢你的建议!是否可以将此移到那个里,或者我应该删除并发布到那个里?我投票将此问题作为离题题结束,因为我已将其移到代码审阅站点。