【问题标题】:Compare Two Dictionaries and Return the Difference比较两个字典并返回差异
【发布时间】:2014-02-11 15:46:25
【问题描述】:

我有两个字典,一个包含原始数据,另一个包含新数据。我想比较两个字典并返回一个字典并返回第三个包含更新的字典。

Dictionary<int, Dictionary<string, string>> OriginalDictionary = new Dictionary
{
    {1, new Dictionary<string, string> 
        {{"name", "adam"}, 
         {"age", "15"}
         {"occupation", "student"}},
    {2, new Dictionary<string, string> 
        {{"name", "bob"}, 
         {"age", "40"}
         {"occupation", "doctor"}},
    {3, new Dictionary<string, string> 
        {{"name", "cameron"}, 
         {"age", "32"}
         {"occupation", "teacher"}},
}

Dictionary<int, Dictionary<string, string>> NewDictionary = new Dictionary
{
    {1, new Dictionary<string, string> 
        {{"name", "adam"}, 
         {"age", "15"}
         {"occupation", "student"}},
    {2, new Dictionary<string, string> 
        {{"name", "bob"}, 
         {"age", "40"}
         {"occupation", "lawyer"}}, //this is where it's different
    {3, new Dictionary<string, string> 
        {{"name", "cameron"}, 
         {"age", "32"}
         {"occupation", "teacher"}},
}

我想获取包含更新的第三个字典。它可以是整个第一层,也可以分解成第二层。以下 2 个示例都适用于我。

Dictionary<int, Dictionary<string, string>> UpdateDictionary1 = new Dictionary
{
    {2, new Dictionary<string, string> 
        {{"name", "bob"}, 
         {"age", "40"}
         {"occupation", "lawyer"}} //this is where it's different
}

Dictionary<int, Dictionary<string, string>> UpdateDictionary2 = new Dictionary
{
    {2, new Dictionary<string, string> 
        {{"occupation", "lawyer"}}
}

我已经尝试了这篇帖子How to compare two Dictionaries in C# 的答案,但我为 UpdateDictionary 获得的结果仍然包含来自 NewDictionary 的所有数据。 UpdatesDictionary.Count == 3,我的预期输出应该是UpdatesDictionary.Count == 1。我尝试了Where 答案和Except 答案,但它们都没有按我希望的那样工作。

UpdateDictionary = OriginalDictionary.Where(entry => NewDictionary[entry.Key] != entry.Value).ToDictionary(entry => entry.Key, entry => entry.Value);

UpdateDictionary = OriginalDictionary.Except(NewDictionary).ToDictionary(x => x.Key, x => x.Value);

我还有其他方法可以解决这个问题吗?

谢谢!

【问题讨论】:

    标签: c# dictionary compare where except


    【解决方案1】:

    首先是简单的部分。查找添加或删除的键:

    var addedKeys = NewDictionary.Keys.Except(OriginalDictionary.Keys);
    var removedKeys = OriginalDictionary.Keys.Except(NewDictionary.Keys);
    

    接下来,要找到已编辑字典的键,我们将为字典创建一个相等比较器,因为尝试内联所有可能的不同方式会太过分了。

    public class DictionaryComparer<TKey, TValue> :
        IEqualityComparer<Dictionary<TKey, TValue>>
    {
        private IEqualityComparer<TValue> valueComparer;
        public DictionaryComparer(IEqualityComparer<TValue> valueComparer = null)
        {
            this.valueComparer = valueComparer ?? EqualityComparer<TValue>.Default;
        }
        public bool Equals(Dictionary<TKey, TValue> x, Dictionary<TKey, TValue> y)
        {
            if (x.Count != y.Count)
                return false;
            if (x.Keys.Except(y.Keys).Any())
                return false;
            if (y.Keys.Except(x.Keys).Any())
                return false;
            foreach (var pair in x)
                if (!valueComparer.Equals(pair.Value, y[pair.Key]))
                    return false;
            return true;
        }
    
        public int GetHashCode(Dictionary<TKey, TValue> obj)
        {
            throw new NotImplementedException();
        }
    }
    

    现在我们有了这个,调用它非常简单:

    var addedKeys = NewDictionary.Keys.Except(OriginalDictionary.Keys);
    var removedKeys = OriginalDictionary.Keys.Except(NewDictionary.Keys);
    var comparer = new DictionaryComparer<string, string>();
    var editedValues = OriginalDictionary.Where(pair =>
        !comparer.Equals(pair.Value, NewDictionary[pair.Key]));
    

    【讨论】:

    • 感谢您的回复。编辑值的数量仍然不正确。我仍然获得了比应有的更多更新:/
    • @sora0419 抱歉,漏掉了一个 NOT ;它正在获取所有相等的字典。
    • 我仍然得到一个更大的计数,所以我尝试使用 Trim() 来消除我不知道的多余空格,并最终让它正常工作(至少是正确的现在我没有看到任何问题)。非常感谢!
    • 我相信您建议的解决方案会生成类似于 UpdateDictionary1 的输出,对吧?您能帮我修改它以生成像 UpdateDictionary2 这样的输出吗?我需要计算每个已更新字段的数量,因此版本 2 会更有意义。抱歉,我之前没有想到这一点
    • @sora0419 您需要创建一个新类型来封装两个字典之间的所有差异,或者至少是您关心的那些差异。添加键、删除键、更改键、新/旧值等。所有这些本质上都是在 Equals 方法中计算的,您只需将这些检查粘贴到该新类型中并返回它,而不是只返回 true /错误的。返回删除的键,返回更改的值。然后在Where 中添加Any 以将其过滤到有任何更改的人。应该相当简单,只是有点乏味。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-03
    • 2014-02-26
    • 1970-01-01
    • 1970-01-01
    • 2021-08-30
    • 1970-01-01
    • 2023-03-03
    相关资源
    最近更新 更多