Как сравнить два словаря в С#

У меня есть два общих словаря. Оба имеют одинаковые ключи. Но значения могут быть разными. Я хочу сравнить 2-й словарь с 1-м словарем. Если есть различия между значениями, я хочу сохранить эти значения в отдельном словаре.

1st Dictionary
------------
key       Value

Barcode   1234566666
Price     20.00


2nd Dictionary
--------------
key       Value

Barcode   1234566666
Price     40.00


3rd Dictionary
--------------
key       Value

Price     40

Кто-нибудь может дать мне лучший алгоритм для этого. Я написал алгоритм, но он имеет много циклов. Я ищу короткую и эффективную идею. Также как решение с использованием выражения запроса LINQ или лямда-выражения LINQ. Я использую .Net Framework 3.5 с С#. Я нашел кое-что о методе Except(). Но, к сожалению, я не мог понять, что происходит с этим методом. Хорошо, если кто-нибудь объяснит предложенный алгоритм.

Ответы

Ответ 1

Если вы уже отметили, что ключи одинаковы, вы можете просто использовать:

var dict3 = dict2.Where(entry => dict1[entry.Key] != entry.Value)
                 .ToDictionary(entry => entry.Key, entry => entry.Value);

Чтобы объяснить, это будет:

  • Итерации по парам ключ/значение в dict2
  • Для каждой записи найдите значение в dict1 и отфильтруйте любые записи, в которых эти два значения совпадают.
  • Создайте словарь из оставшихся записей (т.е. те, где значение dict1 отличается), взяв ключ и значение из каждой пары так же, как они появляются в dict2.

Обратите внимание, что это избегает полагаться на равенство KeyValuePair<TKey, TValue> - на это может положиться положиться, но лично я нахожу это более ясным. (Он также будет работать, когда вы используете собственный сопоставитель сравнений для клавиш словаря - хотя вам также нужно передать это значение в ToDictionary).

Ответ 2

попробуйте:

dictionary1.OrderBy(kvp => kvp.Key)
           .SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))

Ответ 3

Вы упомянули, что оба словаря имеют одинаковые ключи, поэтому, если это предположение верно, вам не нужно ничего фантастического:

        foreach (var key in d1.Keys)
        {
            if (!d1[key].Equals(d2[key]))
            {
                d3.Add(key, d2[key]);
            }
        }

Или я не понимаю вашу проблему?

Ответ 4

чтобы проверить разницу,

dic1.Count == dic2.Count && !dic1.Except(dic2).Any();

следующий код возвращает все разные значения

dic1.Except(dic2) 

Ответ 5

Вы можете присоединиться к ним на своих клавишах и выбрать оба значения. Затем вы можете фильтровать на основе того, являются ли значения одинаковыми или разными. Наконец, вы можете преобразовать коллекцию в словарь с ключами и вторыми значениями.

  var compared = first.Join( second, f => f.Key, s => s.Key, (f,s) => new { f.Key, FirstValue = f.Value, SecondValue = s.Value } )
                      .Where( j => j.FirstValue != j.SecondValue )
                      .ToDictionary( j => j.Key, j => j.SecondValue );

Использование цикла также не должно быть слишком плохим. Я подозреваю, что они будут иметь схожие характеристики.

  var compared = new Dictionary<string,object>();
  foreach (var kv in first)
  {
      object secondValue;
      if (second.TryGetValue( kv.Key, out secondValue ))
      {
            if (!object.Equals( kv.Value, secondValue ))
            {
                compared.Add( kv.Key, secondValue );
            }
      }
  }

Ответ 6

Предполагая, что оба словаря имеют одинаковые ключи, самый простой способ -

var result = a.Except(b).ToDictionary(x => x.Key, x => x.Value);

ИЗМЕНИТЬ

Обратите внимание, что a.Except(b) дает другой результат от b.Except(a):

a.Except(b): Price     20
b.Except(a): Price     40

Ответ 7

var diff1 = d1.Except(d2);
var diff2 = d2.Except(d1);
return diff1.Concat(diff2);

Изменить: Если вы уверены, что все ключи одинаковы, вы можете:

var diff = d2.Where(x=>x.Value != d1[x.Key]).ToDictionary(x=>x.Key, x=>x.Value);

Ответ 8

преобразование объекта в словарь, а затем после того, как концепция набора вычитает их, элементы результата должны быть пустыми, если они идентичны.

 public static IDictionary<string, object> ToDictionary(this object source)
    {
        var fields = source.GetType().GetFields(
            BindingFlags.GetField |
            BindingFlags.Public |
            BindingFlags.Instance).ToDictionary
        (
            propInfo => propInfo.Name,
            propInfo => propInfo.GetValue(source) ?? string.Empty
        );

        var properties = source.GetType().GetProperties(
            BindingFlags.GetField |
            BindingFlags.GetProperty |
            BindingFlags.Public |
            BindingFlags.Instance).ToDictionary
        (
            propInfo => propInfo.Name,
            propInfo => propInfo.GetValue(source, null) ?? string.Empty
        );

        return fields.Concat(properties).ToDictionary(key => key.Key, value => value.Value); ;
    }
    public static bool EqualsByValue(this object source, object destination)
    {
        var firstDic = source.ToFlattenDictionary();
        var secondDic = destination.ToFlattenDictionary();
        if (firstDic.Count != secondDic.Count)
            return false;
        if (firstDic.Keys.Except(secondDic.Keys).Any())
            return false;
        if (secondDic.Keys.Except(firstDic.Keys).Any())
            return false;
        return firstDic.All(pair =>
          pair.Value.ToString().Equals(secondDic[pair.Key].ToString())
        );
    }
    public static bool IsAnonymousType(this object instance)
    {

        if (instance == null)
            return false;

        return instance.GetType().Namespace == null;
    }
    public static IDictionary<string, object> ToFlattenDictionary(this object source, string parentPropertyKey = null, IDictionary<string, object> parentPropertyValue = null)
    {
        var propsDic = parentPropertyValue ?? new Dictionary<string, object>();
        foreach (var item in source.ToDictionary())
        {
            var key = string.IsNullOrEmpty(parentPropertyKey) ? item.Key : $"{parentPropertyKey}.{item.Key}";
            if (item.Value.IsAnonymousType())
                return item.Value.ToFlattenDictionary(key, propsDic);
            else
                propsDic.Add(key, item.Value);
        }
        return propsDic;
    }
originalObj.EqualsByValue(messageBody); // will compare values.

источник кода