Как сравнить два словаря в C # - PullRequest
21 голосов
/ 03 марта 2012

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

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

Ответы [ 8 ]

32 голосов
/ 03 марта 2012

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

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.)

21 голосов
/ 03 марта 2012

попробуй:

dictionary1.OrderBy(kvp => kvp.Key)
           .SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))
12 голосов
/ 03 марта 2012

для проверки любой разницы,

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

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

dic1.Except(dic2) 
11 голосов
/ 03 марта 2012

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

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

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

2 голосов
/ 03 марта 2012
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);
2 голосов
/ 03 марта 2012

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

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
2 голосов
/ 03 марта 2012

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

  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 );
            }
      }
  }
0 голосов
/ 19 января 2018

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

 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.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...