web-dev-qa-db-fra.com

Comment comparer deux dictionnaires en C #

J'ai deux dictionnaires génériques.Les deux ont les mêmes clés.Mais les valeurs peuvent être différentes.Je veux comparer le deuxième dictionnaire avec le 1er dictionnaire.S'il y a des différences entre les valeurs, je veux stocker ces valeurs dans un dictionnaire séparé.

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

Barcode   1234566666
Price     20.00


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

Barcode   1234566666
Price     40.00


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

Price     40

Quelqu'un peut-il me donner un meilleur algorithme pour le faire? J'ai écrit un algorithme, mais il a beaucoup de boucles.Je cherche une idée courte et efficace.Également comme une solution utilisant une expression de requête LINQ ou une expression LINQ lamda.J'utilise. Net Framework 3.5 avec C #. J'ai trouvé quelque chose à propos de la méthode Except () .Mais, malheureusement, je ne comprenais pas ce qui se passait avec cette méthode.Il est génial si quelqu'un explique l'algorithme suggéré.J'aime toujours apprendre :).

Merci Thabo.

18
Thabo

Si vous avez déjà vérifié que les clés sont les mêmes, vous pouvez simplement utiliser:

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

Pour expliquer, cela va:

  • Parcourez les paires clé/valeur dans dict2
  • Pour chaque entrée, recherchez la valeur dans dict1 et filtrez les entrées dont les deux valeurs sont identiques.
  • Formez un dictionnaire à partir des entrées restantes (c'est-à-dire celles où la valeur dict1 est différente) en prenant la clé et la valeur de chaque paire telles qu'elles apparaissent dans dict2.

Notez que cela évite de s’appuyer sur l’égalité de KeyValuePair<TKey, TValue> - il [pourrait peut-être convenir de s'en fier, mais personnellement, je trouve cela plus clair. (Cela fonctionnera également lorsque vous utiliserez un comparateur d'égalité personnalisé pour les clés de dictionnaire - bien que vous deviez également le transmettre à ToDictionary.)

32
Jon Skeet

essayez: 

dictionary1.OrderBy(kvp => kvp.Key)
           .SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))
18
Royi Namir

Vous avez mentionné que les deux dictionnaires ont les mêmes clés. Par conséquent, si cette hypothèse est correcte, vous n'avez besoin de rien d'extraordinaire:

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

Ou est-ce que je comprends mal votre problème?

10
carlosfigueira

pour vérifier toute différence,

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

le code suivant renvoie toutes les valeurs différentes

dic1.Except(dic2) 
8
Chamika Sandamal

Vous devriez pouvoir les joindre sur leurs clés et sélectionner les deux valeurs. Ensuite, vous pouvez filtrer selon que les valeurs sont identiques ou différentes. Enfin, vous pouvez convertir la collection en dictionnaire avec les clés et les deuxièmes valeurs.

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

Utiliser une boucle ne devrait pas être trop mal non plus. Je soupçonne qu'ils auraient des caractéristiques de performance similaires.

  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
tvanfosson

En supposant que les deux dictionnaires aient les mêmes clés, le moyen le plus simple est de

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

MODIFIER

Notez que a.Except(b) donne un résultat différent de b.Except(a):

a.Except(b): Price     20
b.Except(a): Price     40
2
Adi Lester
var diff1 = d1.Except(d2);
var diff2 = d2.Except(d1);
return diff1.Concat(diff2);

Edit: Si vous êtes sûr que toutes les clés sont identiques, vous pouvez faire:

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

convertir l'objet en dictionnaire puis, après les avoir soustraits, les éléments de résultat doivent être vides s'ils sont identiques.

 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.

source du code

0
Mohamed.Abdo