2010-10-13 5 views
35

Je souhaite comparer le contenu de deux instances Dictionary<string, string> sans tenir compte de l'ordre des éléments qu'elles contiennent. SequenceEquals compare également la commande, donc je commande d'abord les dictionnaires par clé, puis appelez SequenceEquals.Comparaison de 2 Dictionary <string, string> Instances

Existe-t-il une méthode que je peux utiliser au lieu de SequenceEquals qui ne fera que comparer le contenu?

Si ce n'est pas le cas, est-ce le moyen idéal de le faire?

Dictionary<string, string> source = new Dictionary<string, string>(); 
Dictionary<string, string> target = new Dictionary<string, string>(); 

source["foo"] = "bar"; 
source["baz"] = "zed"; 
source["blah"] = null; 

target["baz"] = "zed"; 
target["blah"] = null; 
target["foo"] = "bar"; 

// sequenceEquals will be false 
var sequenceEqual = source.SequenceEqual(target); 
// contentsEqual will be true 
var contentsEqual = source.OrderBy(x => x.Key).SequenceEqual(target.OrderBy(x => x.Key)); 
+0

La question contient un très gros défaut. Il n'y a pas d'ordre dans lequel les éléments sont dans un dictionnaire. Par définition, un dictionnaire contient la clé des paires de valeurs sans aucun ordre implicite. – Zordid

Répondre

52
var contentsEqual = source.DictionaryEqual(target); 

// ... 

public static bool DictionaryEqual<TKey, TValue>(
    this IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second) 
{ 
    return first.DictionaryEqual(second, null); 
} 

public static bool DictionaryEqual<TKey, TValue>(
    this IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second, 
    IEqualityComparer<TValue> valueComparer) 
{ 
    if (first == second) return true; 
    if ((first == null) || (second == null)) return false; 
    if (first.Count != second.Count) return false; 

    valueComparer = valueComparer ?? EqualityComparer<TValue>.Default; 

    foreach (var kvp in first) 
    { 
     TValue secondValue; 
     if (!second.TryGetValue(kvp.Key, out secondValue)) return false; 
     if (!valueComparer.Equals(kvp.Value, secondValue)) return false; 
    } 
    return true; 
} 
+0

En ayant des dictionnaires non ordonnés, votre algorithme s'exécute en O (n^2). –

+3

@Yuriy: Comment est-ce O (n^2), en supposant que les hashcodes sont à moitié décents? – LukeH

+0

En supposant que GetHash a été implémenté. –

6

Je ne sais pas s'il y a une méthode existante, mais vous pouvez utiliser les éléments suivants (contrôle nul de args omis par souci de concision)

public static bool DictionaryEquals<TKey,TValue>(
    this Dictionary<TKey,TValue> left, 
    Dictionary<TKey,TValue> right) { 

    var comp = EqualityComparer<TValue>.Default; 
    if (left.Count != right.Count) { 
    return false; 
    } 
    foreach (var pair in left) { 
    TValue value; 
    if (!right.TryGetValue(pair.Key, out value) 
     || !comp.Equals(pair.Value, value)) { 
     return false; 
    } 
    } 
    return true; 
} 

Il serait préférable d'ajouter un surcharge pour permettre la personnalisation du EqualityComparer<TValue>.

0

Cela vérifiera si tous Values de source existe dans target, en ignorant le Keys

var result = source.All(x => target.Any(y => x.Value == y.Value)); 
+4

Cela manque le cas où' target' a des paires de valeurs de clé supplémentaires pas dans 'source' – JaredPar

+0

@JaredPar: Si' target' a de plus paires alors qu'est-ce qui devrait arriver? Renvoie 'false' au lieu de' true'? Puis un contrôle supplémentaire de la longueur le corrigerait-il? – BrunoLM

+1

Je dirais que si le contenu est différent, alors ils ne sont pas égaux. Un contrôle de longueur corrigera le 'target' est plus grand mais pas le problème des clés différentes. – JaredPar

0

Si vous utilisez un SortedDictionary vous ne aurez pas besoin d'appliquer le tri vous-même, qui peut être un peu plus facile à utiliser:

void Main() 
{ 
    var d1 = new Dictionary<string, string> 
    { 
     ["a"] = "Hi there!", 
     ["b"] = "asd", 
     ["c"] = "def" 
    }; 
    var d2 = new Dictionary<string, string> 
    { 
     ["b"] = "asd", 
     ["a"] = "Hi there!", 
     ["c"] = "def" 
    }; 

    var sortedDictionary1 = new SortedDictionary<string, string>(d1); 
    var sortedDictionary2 = new SortedDictionary<string, string>(d2); 

    if (sortedDictionary1.SequenceEqual(sortedDictionary2)) 
    { 
     Console.WriteLine("Match!"); 
    } 
    else 
    { 
     Console.WriteLine("Not match!"); 
    } 
} 
Questions connexes