Pregunta Cómo comparar dos diccionarios en C #


Tengo dos diccionarios genéricos. Ambos tienen las mismas claves. Pero los valores pueden ser diferentes. Quiero comparar el 2 ° diccionario con el 1. ° diccionario. Si hay diferencias entre los valores, quiero almacenar esos valores en un diccionario por separado.

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

Barcode   1234566666
Price     20.00


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

Barcode   1234566666
Price     40.00


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

Price     40

¿Alguien puede darme un mejor algoritmo para hacer esto? Escribí un algoritmo pero tiene muchos bucles. Estoy buscando una idea corta y eficiente. También me gusta una solución usando la expresión de consulta LINQ o la expresión LINQ lamda. Estoy usando. Net Framework 3.5 con C #. Encontré algo sobre el método Except (). Pero desafortunadamente no pude entender lo que está sucediendo en ese método. Es genial si alguien explica el algoritmo sugerido. Siempre me gusta aprender :).

Gracias Thabo.


13
2018-03-03 15:41


origen


Respuestas:


Si ya ha comprobado que las claves son las mismas, puede usar:

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

Para explicar, esto será:

  • Iteramos sobre los pares clave / valor en dict2
  • Para cada entrada, busque el valor en dict1 y filtrar cualquier entrada donde los dos valores sean los mismos
  • Forme un diccionario a partir de las entradas restantes (es decir, aquellas en las que dict1 el valor es diferente) tomando la clave y el valor de cada par tal como aparecen en dict2.

Tenga en cuenta que esto evita confiar en la igualdad de KeyValuePair<TKey, TValue> - eso podría estar bien para confiar en eso, pero personalmente me parece más claro. (También funcionará cuando utilice un comparador de igualdad personalizado para las teclas del diccionario, aunque deberá pasarlo a ToDictionary, también.)


29
2018-03-03 15:57



tratar :

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

17
2018-03-03 15:50



Usted mencionó que ambos diccionarios tienen las mismas claves, por lo que si esta suposición es correcta, no necesita nada sofisticado:

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

¿O estoy malinterpretando tu problema?


8
2018-03-03 15:48



para verificar cualquier diferencia,

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

el siguiente código devuelve todos los valores diferentes

dic1.Except(dic2) 

7
2018-03-03 15:55



Debería poder unirlos en sus claves y seleccionar ambos valores. Luego puede filtrar según si los valores son iguales o diferentes. Finalmente, puede convertir la colección en un diccionario con las claves y los segundos valores.

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

Usar un bucle no debería ser tan malo tampoco. Sospecho que tendrían características de rendimiento similares.

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

2
2018-03-03 15:49



Suponiendo que ambos diccionarios tienen las mismas claves, la forma más simple es

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

EDITAR

Tenga en cuenta que a.Except(b) da un resultado diferente de b.Except(a):

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

2
2018-03-03 15:53



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

Editar: Si está seguro de que todas las teclas son las mismas, puede hacerlo:

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

2
2018-03-03 15:54



al convertir el objeto al diccionario, luego de seguir el concepto, restáurelos, los ítems de resultado deben estar vacíos en caso de que sean idénticos.

 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.

fuente del código


0
2018-01-19 18:32