Compare 2 List<Dictionary<string, object>>
I have a function which returns a List<Dictionary<string, object>>
where object is a standard type (string, int, etc).
I need to take a second List<Dictionary<string, object>>
and ensure that All entries in list B are represented in List A (order in the list does not matter).
Currently I have code that looks like this:
foreach(Dictionary<string, object> rowResult in A) {
foreach(Dictionary<string, object> ro开发者_开发技巧wCompare in B) {
foreach(string columnName in rowResult.Keys) {
// ... logic to compare columns
}
}
// ...logic to compare rows so we dont find the same row twice.
}
Is there a more straightforward way to do this?
We dont care that all rows in rowResult are found, but all rows in rowCompare must be. It is ok to remove rows from the compare or result set to make the iteration easier.
My code works, it just looks over complicated and fragile.
class DictionaryComparer<TKey, TValue> : IEqualityComparer<Dictionary<TKey, TValue>> {
public bool Equals(Dictionary<TKey, TValue> x, Dictionary<TKey, TValue> y) {
if (x == null) {
throw new ArgumentNullException("x");
}
if (y == null) {
throw new ArgumentNullException("y");
}
if (x.Count != y.Count) {
return false;
}
foreach (var kvp in x) {
TValue value;
if(!y.TryGetValue(kvp.Key, out value)) {
return false;
}
if(!kvp.Value.Equals(value)) {
return false;
}
}
return true;
}
public int GetHashCode(Dictionary<TKey, TValue> obj) {
if (obj == null) {
throw new ArgumentNullException("obj");
}
int hash = 0;
foreach (var kvp in obj) {
hash = hash ^ kvp.Key.GetHashCode() ^ kvp.Value.GetHashCode();
}
return hash;
}
}
Then:
public bool Contains(
List<Dictionary<string, object>> first,
List<Dictionary<string, object>> second) {
if(first == null) {
throw new ArgumentNullException("first");
}
if(second == null) {
throw new ArgumentNullException("second");
}
IEqualityComparer<Dictionary<string, object>> comparer = new DictionaryComparer<string, object>();
return second.All(y => first.Contains(y, comparer));
}
Well... what are you doing this for? The reason I ask is that there's this hyper useful Unit Testing method called CollectionAssert.AreEquivalent.
From the remarks section:
Two collections are equivalent if they have the same elements in the same quantity, but in any order. Elements are equal if their values are equal, not if they refer to the same object.
It looks like it does exactly what you want, and throws AssertFailedException if the two are not equivalent, which may also be what you want. Is there any way to leverage it? One method call is certainly far greater than a triple-nested loop -- even if that's what the method does under the covers.
foreach(Dictionary<string, object> rowCompare in B)
if(!A.Contains(rowCompare)) return false;
return true;
Assuming your comparators are set up appropriately, this will work. And is straightforward and easy to understand. You can even add the braces back in if you find it easier that way.
精彩评论