2010-10-13 14 views
35

Quiero comparar el contenido de dos instancias Dictionary<string, string> independientemente del orden de los elementos que contienen. SequenceEquals también compara el orden, así que primero ordeno los diccionarios por clave y luego llamo al SequenceEquals.Comparando 2 Diccionario <cadena, cadena> Instancias

¿Hay algún método que pueda usar en lugar de SequenceEquals que solo compare el contenido?

Si no lo hay, ¿es esta la forma ideal de hacerlo?

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 pregunta contiene un gran defecto. No existe tal cosa como un orden en el que los elementos están en un diccionario. Por definición, un diccionario tiene la clave para pares de valores sin ningún orden implícito. – Zordid

Respuesta

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

Al tener diccionarios desordenados, su algoritmo se ejecuta en O (n^2). –

+3

@Yuriy: ¿Cómo es O (n^2), suponiendo que los códigos hash son medio decentes? – LukeH

+0

Suponiendo que se implementó GetHash. –

6

No sé si hay un método existente pero se puede usar el siguiente (comprobación nula de args omitido por razones de brevedad)

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

Lo mejor sería añadir una sobrecarga para permitir la personalización del EqualityComparer<TValue>.

0

Esto comprobará si todo Values de source existe en target, ignorando el Keys

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

Esto echa de menos el caso donde' target' tiene pares de valores clave adicionales no en 'source' – JaredPar

+0

@JaredPar: If' target' tiene adicional pares entonces, ¿qué debería pasar? ¿Devuelve 'falso' en lugar de' verdadero'? Entonces, un control adicional para la longitud lo arreglaría, ¿verdad? – BrunoLM

+1

Diría que si los contenidos son diferentes, entonces no son iguales. Una verificación de longitud arreglaría que el 'objetivo' sea más grande pero no el problema de que las claves sean diferentes. – JaredPar

0

Si utiliza un SortedDictionary no será necesario aplicar la clasificación a sí mismo, que puede ser un poco más fácil de usar:

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!"); 
    } 
} 
Cuestiones relacionadas