2011-12-14 14 views
5

que tienen la siguiente estructura de datos:¿Cómo hacer comparación de valores entre dos Dictionary <string, lista <string>> objetos

Dictionary<string, List<string>> 

¿Cómo puedo hacer la comparación para asegurarse de que los valores son iguales entre dos objetos diferentes?

es decir:

Dictionary<string, List<string>> expected = new Dictionary<string, List<string>>(); 
    expected.Add("CREDIT", new List<string> { "K R EH D IH T" }); 
    expected.Add("CARD", new List<string> { "K AA R D" }); 

    Dictionary<string, List<string>> actual; 
    actual = target.GetTermDictionary(); 
    if (!Enumerable.SequenceEqual(expected, actual)) 
    { 
     Assert.Fail(); 
    } 

No creo que SequanceEqual es bueno aquí ..

Gracias

+0

¿Exige que los elementos de cada lista para estar en el mismo orden? – Rawling

+0

No creo que haya un método integrado. Eche un vistazo aquí: http://stackoverflow.com/questions/3928822/comparing-2-dictionarystring-string-instances –

+0

sí, todo debería ser el mismo, los mismos valores, mismo orden – user829174

Respuesta

3

primer acceso directo en trues rápidas y Falsas:

if(ReferenceEqual(actual, expected)) 
    return true; 
if(actual == null || expected == null || actual.Count != expected.Count) 
    return false; 

Esto también maneja nulo comprobando así que todo lo demás que do no puede lanzar una excepción de referencia nula. Puede omitir toda esta barra comparando los recuentos si los tiene justo después de la creación como en su ejemplo, pero debe guardarlos si los pone en un método diferente, por si acaso.

No podemos simplemente llamar a SequenceEqual en los dos diccionarios, porque no tenemos la garantía de recuperar las claves en el mismo orden. Con otros tipos para el valor que podíamos hacer:

return actual.OrderBy(kvp => kvp.Key).SequenceEqual(expected.OrderBy(kvp => kvp.Key)); 

Pero esto no va a funcionar porque los dos valores de secuencia List<string>-iguales no serán consideradas iguales al método DefaultEqualityComparer<List<string>>.Equals() que esto va a poner en.

podríamos crear un IEqualityComparer<KeyValuePair<string, List<string>>> si estábamos obligados-demonios en el uso de SequenceEqual, pero es probablemente más fácil de hacer el enfoque no LINQ, a pesar de que LINQ es normalmente más sencilla y concisa (una vez que encuentre la manera de hacerlo. Por lo tanto:..

List<string> expectedVal; 
foreach(KeyValuePair<string, List<string> kvp in actual) 
{ 
    if(!expected.TryGetValue(kvp.key, out expectedVal) || kvp.Value.Count != expectedVal.Count || !kvp.Value.SequenceEquals(expectedVal)) 
    return false; 

} 
return true; 

variantes pueden tratar con diferentes puntos de vista de la igualdad Por ejemplo, podemos utilizar kvp.Value.OrderBy(x => x).SequenceEquals(expectedVal.OrderBy(x => x)) si quisiéramos considerar dos listas de los mismos artículos en diferentes órdenes como igual

en resumen, el mucho juntos:

if(ReferenceEqual(actual, expected)) 
    return true; 
if(actual == null || expected == null || actual.Count != expected.Count) 
    return false; 
List<string> expectedVal; 
foreach(KeyValuePair<string, List<string> kvp in actual) 
{ 
    if(!expected.TryGetValue(kvp.key, out expectedVal) || kvp.Value.Count != expectedVal.Count || !kvp.Value.SequenceEquals(expectedVal)) 
    return false; 

} 
return true; 

Editar: Sólo por diversión, la forma en que utiliza SequenceEquals:

internal class KvpSLSEq : IEqualityComparer<KeyValuePair<string, List<string>>> 
{ 
    public bool Equals(KeyValuePair<string, List<string>> x, KeyValuePair<string, List<string>> y) 
    { 
    return x.Key == y.Key && x.Value.Count == y.Value.Count && x.Value.SequenceEquals(y.Value); 
    } 
    public int GetHashCode(KeyValuePair<string, List<string>> obj) 
    { 
    //you could just throw NotImplementedException unless you'll reuse this elsewhere. 
    int hash = obj.Key.GetHashCode; 
    foreach(string val in obj.Value) 
     hash = hash * 31 + (val == null ? 0 : val.GetHashCode()); 
    } 
} 

Este hecho se puede utilizar la concisa:

actual.OrderBy(kvp => kvp.Key).SequenceEqual(expected.OrderBy(kvp => kvp.Key), new KvpSLSEq()); 

pero es sólo muy concisa si KvpSLSEq se utiliza en otros lugares también.

1

No creo que haya construido en el método, pero se puede comparar la lista valores dentro de cada entrada del diccionario. Algo como esto:

// Check actual doesn't contain excess keys 
if (actual.Keys.Count != expected.Keys.Count) 
{ 
    return false; 
} 

foreach(var key in expected.Keys) 
{ 
    if (!actual.ContainsKey(key) || !actual[key].SequenceEqual(expected[key])) 
    { 
     return false; 
    } 
} 

return true; 

Echa un vistazo aquí: Comparing 2 Dictionary<string, string> Instances y aquí: Is there a built-in method to compare collections in C#?

+1

También es necesario verificar que real no contenga ningún exceso de claves. – Rawling

+1

Gracias, creo que mi edición lo hará –

+0

Lo hará, y también atajo en cualquier caso donde cualquiera de los dos sea más corto para aumentar el rendimiento. Yo usaría 'real.TryGetValue' por mi cuenta, así puedo pasar la verificación de la tecla contains y obtener la lista en uno. –

Cuestiones relacionadas