2011-12-14 10 views
5

Ho la seguente struttura dei dati:Come fare il confronto valore compreso tra due Dictionary <string, Lista <string>> oggetti

Dictionary<string, List<string>> 

come posso fare il confronto per assicurarsi che i valori sono uguali tra due oggetti diversi?

vale a dire:

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

Non credo che SequanceEqual è buono qui ..

Grazie

+0

Avete bisogno gli elementi in ciascuna lista per essere nello stesso ordine? – Rawling

+0

Non penso che ci sia un metodo integrato. Date un'occhiata qui: http://stackoverflow.com/questions/3928822/comparing-2-dictionarystring-string-instances –

+0

sì, tutto dovrebbe essere lo stesso, stessi valori, nello stesso ordine – user829174

risposta

3

primo collegamento sul Trues veloci e falses:

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

Questo gestisce anche nullo-checking quindi tutto il resto abbiamo non può lanciare un'eccezione di riferimento null. Puoi saltare tutta questa barra confrontando i conteggi se li hai appena dopo la creazione come nel tuo esempio, ma dovresti tenerlo dentro se lo metti in un metodo separato, per ogni evenienza.

Non possiamo semplicemente chiamare SequenceEqual sui due dizionari, perché non è garantito il recupero delle chiavi nello stesso ordine. Con altri tipi per il valore che si potrebbe fare:

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

Ma questo non funzionerà perché i due List<string> valori della sequenza-parità non sarà considerato uguale al metodo DefaultEqualityComparer<List<string>>.Equals() che ciò mettere in.

potremmo creare un IEqualityComparer<KeyValuePair<string, List<string>>> se fossimo inferno-vincolati sull'uso SequenceEqual, ma è probabilmente più semplice per fare l'approccio non-Linq, anche se Linq è normalmente più semplice e concisa (una volta trovato il modo di farlo. Quindi:..

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; 

varianti possono trattare con diversi punti di vista di uguaglianza, ad esempio, possiamo utilizzare kvp.Value.OrderBy(x => x).SequenceEquals(expectedVal.OrderBy(x => x)) se volessimo considerare due liste degli stessi articoli in diversi ordini come uguale

in sintesi, il lotto:

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; 

Edit: Solo per divertimento, il modo in cui utilizza 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()); 
    } 
} 

Fatto questo possiamo usare la concisa:

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

ma è veramente solo concisa se KvpSLSEq verrà utilizzato altrove anche.

1

Non credo che ci sia costruito nel metodo, ma è possibile confrontare l'elenco valori all'interno di ogni voce del dizionario. Qualcosa di simile a questo:

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

dare uno sguardo qui: Comparing 2 Dictionary<string, string> Instances e qui: Is there a built-in method to compare collections in C#?

+1

Inoltre, è necessario verificare che il reale non contenga tasti in eccesso. – Rawling

+1

Grazie, penso che la mia modifica lo farà –

+0

Sarà, e anche scorciatoia in ogni caso dove sia più breve per un aumento delle prestazioni. Userò me stesso 'actual.TryGetValue', così posso eseguire il controllo dei tasti contiene e ottenere l'elenco in uno solo. –

Problemi correlati