-1

问题移到这里

我的要求是编写一个模仿差异工具的程序。是的,有很多库和开源代码可以实现这个目的,但我想编写自己的比较器。

这是起点。我有一个名为 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; }
}

我有两个这些类对象的列表,我们称它们为 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 视为完成一些更改后的列表。我想比较两者,并将它们分为三类:

  1. 已添加项目 - 将新“数据”添加到列表中的项目。
  2. 已移除项目 - 已从列表中移除项目。
  3. Diff Items - 在 PRE 和 POST 列表中都可以找到“数据”,但它们对应的“值”不同。

因此,分类时,它们应如下所示:

Added Items:
EEE,9

Removed Items:
CCC,3
GGG,3

Diff Items:
BBB
FFF

我有另一个 DiffItem 类,我想将最终结果放入其中的对象。DiffItem 看起来像这样:

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();
    }
}

然后使用 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));
        }
    }

这确实有效并完成了工作。但我想知道是否有“更好”的方法来做到这一点。请注意,我在“更好”这个词周围加上了引号,因为我没有正确的定义来说明什么会使它变得更好。也许有没有办法在没有尽可能多的“foreach”循环和使用 except() 和 Intersetc() 的情况下完成这项工作,因为我想在 Linq 背后有相当多的迭代正在进行。

简而言之,有没有我可以为此编写的更简洁的代码?我主要是出于学术兴趣和扩展我的知识。

4

1 回答 1

0

我认为您不需要 IEqualityComparer:

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);
于 2017-07-18T00:29:56.277 回答