I can't figure out how to keep the keys and values on a dictionary when I try to merge two dictionaries. I keep getting ArgumentException due to duplicate of key. When the key match I would just like to add the value by =+ kvp.value;
I have a list of Dictionaries where the
1st Dictionary = kvp = "jump", 2;
2ndDictionary = kvp = "jump", 4;
I like to merge them and get something like:
Dictionary = kvp = "jump", 6;
That I can later add to my list of Dictionaries
I've tried to run something I found in StackOverflow thread.
foreach (var dict in listOfDict)
{
dict.SelectMany(d => d)
.ToLookup(pair => pair.Key, pair => pair.Value)
.ToDictionary(group => group.Key, group => group.First());
}
But I keep getting.
cannot be inferred from the usage. Try specifying the type arguments
explicitly.
I want to avoid getting all keys and all values on separate lists that I later loop through to add key and value on a new dictionary.
Simplest extension to list of dictionary of double values with using Linq:
public static class ExtListOfDict {
public static Dictionary<TKey, double> SumValue1<TKey>(this List<Dictionary<TKey, double>> list)
=> list?.SelectMany(i => i).ToLookup(i => i.Key, i => i.Value).ToDictionary(i => i.Key, i => i.Sum());
}
without linq:
public static Dictionary<TKey, double> SumValue2<TKey>(this List<Dictionary<TKey, double>> list) {
if(list?.Count > 0) {
var dir = new Dictionary<TKey, double>(list[0]);
for(var i = 1; i < list.Count; i++)
foreach (var kv in list[i])
if (dir.TryGetValue(kv.Key, out double sum))
dir[kv.Key] = sum + kv.Value;
else
dir.Add(kv.Key, kv.Value);
return dir;
} else
return null;
}
If you like the LINQ approach, I would go with something like this:
var dictionaries = new List<Dictionary<string, int>>(); // this is the list of dictionaries you want to merge
var unifiedDictionary = new Dictionary<string, int>(); // this is the dictionary where you merge and add the values
foreach (var kvp in dictionaries.SelectMany(dictionary => dictionary))
{
if (unifiedDictionary.ContainsKey(kvp.Key))
{
unifiedDictionary[kvp.Key] += kvp.Value;
}
else
{
unifiedDictionary.Add(kvp.Key, kvp.Value);
}
}
However, if this is too hard to read (I am not always a fan of excessive LINQ over explicit code blocks), you can use the for-loop approach:
var dictionaries = new List<Dictionary<string, int>>(); // this is the list of dictionaries you want to merge
var unifiedDictionary = new Dictionary<string, int>(); // this is the dictionary where you merge and add the values
foreach (var dictionary in dictionaries)
{
foreach (var kvp in dictionary)
{
if (unifiedDictionary.ContainsKey(kvp.Key))
{
unifiedDictionary[kvp.Key] += kvp.Value;
}
else
{
unifiedDictionary.Add(kvp.Key, kvp.Value);
}
}
}
Hope this helps you. If further help and explanations are needed, please tell me.
Here is a solution based on the CollectionsMarshal.GetValueRefOrAddDefault API (.NET 6), and on the INumber<TSelf> interface (.NET 7):
public static Dictionary<TKey, TValue> ToSumDictionary<TKey, TValue>(
this IEnumerable<Dictionary<TKey, TValue>> dictionaries)
where TValue : struct, INumber<TValue>
{
ArgumentNullException.ThrowIfNull(dictionaries);
Dictionary<TKey, TValue> result = null;
foreach (var dictionary in dictionaries)
{
if (result is null)
{
result = new(dictionary, dictionary.Comparer);
continue;
}
if (!ReferenceEquals(dictionary.Comparer, result.Comparer))
throw new InvalidOperationException("Incompatible comparers.");
foreach (var (key, value) in dictionary)
{
ref TValue refValue = ref CollectionsMarshal
.GetValueRefOrAddDefault(result, key, out bool exists);
refValue = exists ? refValue + value : value;
}
}
result ??= new();
return result;
}
The key of each KeyValuePair<TKey, TValue> in each dictionary is hashed only once.
If you are getting an exception due to duplicate keys, then it sounds like you have duplicate keys!
Have you checked the two dictionaries before you try to merge them? Simply calling =+ kvp.value without checking to see if the first dictionary already has a key of that name is very likely to be your problem.
You need to check for an existing entry with that key, and if one is found, take whatever action is appropriate for your scenario (ie ignore, overwrite, ask the user to decide, etc)
i have two Dictionarys A & B, i want to see if all entries in A exist in B. In the past i've compared Lists using the following:
var set1 = new HashSet<String>(list1);
var set2 = new HashSet<String>(list2);
return set1.SetEquals(set2);
What i have thought to do is simply loop over each value in Dictionary A using:
dictA.TryGetValue(dictBvalue, out item)
this will return null on the item var if the value isn't there, but this seems a little long winded.
Is there a quick and effcient way of comparing dictionaries?
Thanks.
You could use All extension and do this.
var allexist = list1.All(x=> list2.ContainsKey(x.Key) && list2[x.Key] == x.Value)
here is the solution if you want to loop over each value
Dictionary<string, string> dictA = new Dictionary<string, string>();
Dictionary<string, string> dictB = new Dictionary<string, string>();
bool allexist = true;
foreach (var itemA in dictA)
{
if (!dictB.ContainsKey(itemA.Key))
{
allexist = false;
}
}
Actually, you asked for a method comparing dictionaries but your code example refer to HashSet which is different.
For HashSets, you can use IsSubsetOf and SetEquals methods.
To compare dictionaries, you can use DictionaryEquals method from this answer
I am working with a list of dictionaries containing string arrays. The dictionaries are defined/filled via a loop over a DataTable. In the following code test evaluates to false (twice), can somebody tell me why?
List<Dictionary<string[], int>> mydix = new List<Dictionary<string[], int>>();
mydix.Add(new Dictionary<string[], int>());
mydix.Add(new Dictionary<string[], int>());
mydix.Add(new Dictionary<string[], int>());
string[] s = {"tree"};
mydix[1].Add(s, 1);
bool test = mydix[1].ContainsKey(s); // This evaluates to true, which I understand
var entry= mydix[1][s]; // This is 1
DataTable dt=new DataTable();
dt.Columns.Add("test");
dt.Rows.Add(new string[] {"key"});
mydix[2].Add(dt.Rows[0].ItemArray.Select(x => x.ToString()).ToArray(), 2);
test = mydix[2].ContainsKey(new string[] { "key" }); // Why does this evaluate to false?
// Here is an example with an array with two elements
DataTable dt2 = new DataTable();
dt2.Columns.Add("test");
dt2.Columns.Add("test2");
string[] t={"tree1","tree2"};
dt2.Rows.Add(t);
mydix[0].Add(dt2.Rows[0].ItemArray.Select(x => x.ToString()).ToArray(), 3);
test = mydix[0].ContainsKey(t); // Why does this evaluate to false?
The problem is that the string array you are using as the key to the dictionary does object comparison, not content comparison.
In order to support this type of data as a key, the easiest solution is to use an IEqualityComparer.
First, create the comparer (this is a sample; yours will need additional sanity checking and logic):
private class ArrayComparer : IEqualityComparer<string[]>
{
public bool Equals(string[] item1, string[] item2)
{
if (item1[0] == item2[0])
{
return true;
}
else
{
return false;
}
}
public int GetHashCode(string[] item)
{
return item[0].GetHashCode();
}
Then, change the instantiation of your dictionaries to use this new comparer:
mydix.Add(new Dictionary<string[], int>(new ArrayComparer()));
mydix.Add(new Dictionary<string[], int>(new ArrayComparer()));
mydix.Add(new Dictionary<string[], int>(new ArrayComparer()));
Once you have done this, both tests will return true.
Hopefully someone will correct me if I'm wrong, but it's my understanding that when you call ContainsKey, the Dictionary has a private method (exploring in dotPeek), which runs to decide wether the objects you're comparing are equal or not.
Depending on what type you're using for the key, a different equality comparison will occur, based on various implementations of IEqualityComparer, this way the most appropriate comparison can be run, based on the types you wish to compare.
You're using string arrays as the keys, so you're essentially checking the equality of the array objects themselves, not their contents. So it's entirely correct that your ContainsKey is returning false, you aren't asking your Dictionary if it contains the same array as a key, you're asking it if it contains a different array, which happens to contain the same contents.
The IEqualityComparer GetHashCode method in this case (an array), will return a hash based on the reference of the object, not the contents.
If you wanted this behaviour, the magic Mr Skeet has written a custom IEqualityComparer<T> for arrays in this post:
Compare Objects?
Using C#, I want to compare two dictionaries to be specific, two dictionaries with the same keys but not same values, I found a method Comparer but I'm not quite sure how can I use it? Is there a way other than iterating through each key?
Dictionary
[
{key : value}
]
Dictionary1
[
{key : value2}
]
If all you want to do is see if the keys are different but not know what they are, you can use the SequenceEqual extension method on the Keys property of each dictionary:
Dictionary<string,string> dictionary1;
Dictionary<string,string> dictionary2;
var same = dictionary1.Count == dictionary2.Count && dictionary1.Keys.SequenceEqual(dictionary2.Keys);
If you want the actual differences, something like this:
var keysDictionary1HasThat2DoesNot = dictionary1.Keys.Except(dictionary2.Keys);
var keysDictionary2HasThat1DoesNot = dictionary2.Keys.Except(dictionary1.Keys);
return dict1.Count == dict2.Count &&
dict1.Keys.All(dict2.ContainsKey);
Try this
public bool SameKeys<TKey, TValue>(IDictionary<TKey, TValue> one, IDictionary<TKey, TValue> two)
{
if (one.Count != two.Count)
return false;
foreach (var key in one.Keys)
{
if (!two.ContainsKey(key))
return false;
}
return true;
}
You can get a collection of the keys and index it, if that helps.
dictionary1.keys[0] == dictionary2.keys[5]
I'm actually not sure if you index it with a number or if you do it with the key itself, so try out both.
You could go with this (depending if you want the intersect or the exclusion):
Dictionary<int, int> dict1 = new Dictionary<int, int>();
Dictionary<int, int> dict2 = new Dictionary<int, int>();
IEnumerable<int> keys1ExceptKeys2 = dict1.Keys.Except(dict2.Keys);
IEnumerable<int> keys2ExceptKeys1 = dict2.Keys.Except(dict1.Keys);
IEnumerable<int> keysIntersect = dict1.Keys.Intersect(dict2.Keys);
You could just:
new HashSet<TKey>(dictionary1.Keys).SetEquals(dictionary2.Keys)
Be careful if dictionary1 uses a different comparer from dictionary2. You'll have to decide whether "equality" means what one or the other dictionary thinks it means (or something else entirely)...
I would like to compare the contents of a couple of collections in my Equals method. I have a Dictionary and an IList. Is there a built-in method to do this?
Edited:
I want to compare two Dictionaries and two ILists, so I think what equality means is clear - if the two dictionaries contain the same keys mapped to the same values, then they're equal.
Enumerable.SequenceEqual
Determines whether two sequences are equal by comparing their elements by using a specified IEqualityComparer(T).
You can't directly compare the list & the dictionary, but you could compare the list of values from the Dictionary with the list
As others have suggested and have noted, SequenceEqual is order-sensitive. To solve that, you can sort the dictionary by key (which is unique, and thus the sort is always stable) and then use SequenceEqual. The following expression checks if two dictionaries are equal regardless of their internal order:
dictionary1.OrderBy(kvp => kvp.Key).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))
EDIT: As pointed out by Jeppe Stig Nielsen, some object have an IComparer<T> that is incompatible with their IEqualityComparer<T>, yielding incorrect results. When using keys with such an object, you must specify a correct IComparer<T> for those keys. For example, with string keys (which exhibit this issue), you must do the following in order to get correct results:
dictionary1.OrderBy(kvp => kvp.Key, StringComparer.Ordinal).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key, StringComparer.Ordinal))
In addition to the mentioned SequenceEqual, which
is true if two lists are of equal length and their corresponding
elements compare equal according to a comparer
(which may be the default comparer, i.e. an overriden Equals())
it is worth mentioning that in .Net4 there is SetEquals on ISet objects,
which
ignores the order of elements and any duplicate elements.
So if you want to have a list of objects, but they don't need to be in a specific order, consider that an ISet (like a HashSet) may be the right choice.
Take a look at the Enumerable.SequenceEqual method
var dictionary = new Dictionary<int, string>() {{1, "a"}, {2, "b"}};
var intList = new List<int> {1, 2};
var stringList = new List<string> {"a", "b"};
var test1 = dictionary.Keys.SequenceEqual(intList);
var test2 = dictionary.Values.SequenceEqual(stringList);
This is not directly answering your questions, but both the MS' TestTools and NUnit provide
CollectionAssert.AreEquivalent
which does pretty much what you want.
I didn't know about Enumerable.SequenceEqual method (you learn something every day....), but I was going to suggest using an extension method; something like this:
public static bool IsEqual(this List<int> InternalList, List<int> ExternalList)
{
if (InternalList.Count != ExternalList.Count)
{
return false;
}
else
{
for (int i = 0; i < InternalList.Count; i++)
{
if (InternalList[i] != ExternalList[i])
return false;
}
}
return true;
}
Interestingly enough, after taking 2 seconds to read about SequenceEqual, it looks like Microsoft has built the function I described for you.
.NET Lacks any powerful tools for comparing collections. I've developed a simple solution you can find at the link below:
http://robertbouillon.com/2010/04/29/comparing-collections-in-net/
This will perform an equality comparison regardless of order:
var list1 = new[] { "Bill", "Bob", "Sally" };
var list2 = new[] { "Bob", "Bill", "Sally" };
bool isequal = list1.Compare(list2).IsSame;
This will check to see if items were added / removed:
var list1 = new[] { "Billy", "Bob" };
var list2 = new[] { "Bob", "Sally" };
var diff = list1.Compare(list2);
var onlyinlist1 = diff.Removed; //Billy
var onlyinlist2 = diff.Added; //Sally
var inbothlists = diff.Equal; //Bob
This will see what items in the dictionary changed:
var original = new Dictionary<int, string>() { { 1, "a" }, { 2, "b" } };
var changed = new Dictionary<int, string>() { { 1, "aaa" }, { 2, "b" } };
var diff = original.Compare(changed, (x, y) => x.Value == y.Value, (x, y) => x.Value == y.Value);
foreach (var item in diff.Different)
Console.Write("{0} changed to {1}", item.Key.Value, item.Value.Value);
//Will output: a changed to aaa
To compare collections you can also use LINQ. Enumerable.Intersect returns all pairs that are equal. You can comparse two dictionaries like this:
(dict1.Count == dict2.Count) && dict1.Intersect(dict2).Count() == dict1.Count
The first comparison is needed because dict2 can contain all the keys from dict1 and more.
You can also use think of variations using Enumerable.Except and Enumerable.Union that lead to similar results. But can be used to determine the exact differences between sets.
How about this example:
static void Main()
{
// Create a dictionary and add several elements to it.
var dict = new Dictionary<string, int>();
dict.Add("cat", 2);
dict.Add("dog", 3);
dict.Add("x", 4);
// Create another dictionary.
var dict2 = new Dictionary<string, int>();
dict2.Add("cat", 2);
dict2.Add("dog", 3);
dict2.Add("x", 4);
// Test for equality.
bool equal = false;
if (dict.Count == dict2.Count) // Require equal count.
{
equal = true;
foreach (var pair in dict)
{
int value;
if (dict2.TryGetValue(pair.Key, out value))
{
// Require value be equal.
if (value != pair.Value)
{
equal = false;
break;
}
}
else
{
// Require key be present.
equal = false;
break;
}
}
}
Console.WriteLine(equal);
}
Courtesy : https://www.dotnetperls.com/dictionary-equals
For ordered collections (List, Array) use SequenceEqual
for HashSet use SetEquals
for Dictionary you can do:
namespace System.Collections.Generic {
public static class ExtensionMethods {
public static bool DictionaryEquals<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> d1, IReadOnlyDictionary<TKey, TValue> d2) {
if (object.ReferenceEquals(d1, d2)) return true;
if (d2 is null || d1.Count != d2.Count) return false;
foreach (var (d1key, d1value) in d1) {
if (!d2.TryGetValue(d1key, out TValue d2value)) return false;
if (!d1value.Equals(d2value)) return false;
}
return true;
}
}
}
(A more optimized solution will use sorting but that will require IComparable<TValue>)
No, because the framework doesn't know how to compare the contents of your lists.
Have a look at this:
http://blogs.msdn.com/abhinaba/archive/2005/10/11/479537.aspx
public bool CompareStringLists(List<string> list1, List<string> list2)
{
if (list1.Count != list2.Count) return false;
foreach(string item in list1)
{
if (!list2.Contains(item)) return false;
}
return true;
}
There wasn't, isn't and might not be, at least I would believe so. The reason behind is collection equality is probably an user defined behavior.
Elements in collections are not supposed to be in a particular order though they do have an ordering naturally, it's not what the comparing algorithms should rely on. Say you have two collections of:
{1, 2, 3, 4}
{4, 3, 2, 1}
Are they equal or not? You must know but I don't know what's your point of view.
Collections are conceptually unordered by default, until the algorithms provide the sorting rules. The same thing SQL server will bring to your attention is when you trying to do pagination, it requires you to provide sorting rules:
https://learn.microsoft.com/en-US/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017
Yet another two collections:
{1, 2, 3, 4}
{1, 1, 1, 2, 2, 3, 4}
Again, are they equal or not? You tell me ..
Element repeatability of a collection plays its role in different scenarios and some collections like Dictionary<TKey, TValue> don't even allow repeated elements.
I believe these kinds of equality are application defined and the framework therefore did not provide all of the possible implementations.
Well, in general cases Enumerable.SequenceEqual is good enough but it returns false in the following case:
var a = new Dictionary<String, int> { { "2", 2 }, { "1", 1 }, };
var b = new Dictionary<String, int> { { "1", 1 }, { "2", 2 }, };
Debug.Print("{0}", a.SequenceEqual(b)); // false
I read some answers to questions like this(you may google for them) and what I would use, in general:
public static class CollectionExtensions {
public static bool Represents<T>(this IEnumerable<T> first, IEnumerable<T> second) {
if(object.ReferenceEquals(first, second)) {
return true;
}
if(first is IOrderedEnumerable<T> && second is IOrderedEnumerable<T>) {
return Enumerable.SequenceEqual(first, second);
}
if(first is ICollection<T> && second is ICollection<T>) {
if(first.Count()!=second.Count()) {
return false;
}
}
first=first.OrderBy(x => x.GetHashCode());
second=second.OrderBy(x => x.GetHashCode());
return CollectionExtensions.Represents(first, second);
}
}
That means one collection represents the other in their elements including repeated times without taking the original ordering into account. Some notes of the implementation:
GetHashCode() is just for the ordering not for equality; I think it's enough in this case
Count() will not really enumerates the collection and directly fall into the property implementation of ICollection<T>.Count
If the references are equal, it's just Boris
I've made my own compare method. It returns common, missing, and extra values.
private static void Compare<T>(IEnumerable<T> actual, IEnumerable<T> expected, out IList<T> common, out IList<T> missing, out IList<T> extra) {
common = new List<T>();
missing = new List<T>();
extra = new List<T>();
var expected_ = new LinkedList<T>( expected );
foreach (var item in actual) {
if (expected_.Remove( item )) {
common.Add( item );
} else {
extra.Add( item );
}
}
foreach (var item in expected_) {
missing.Add( item );
}
}
Comparing dictionaries' contents:
To compare two Dictionary<K, V> objects, we can assume that the keys are unique for every value, thus if two sets of keys are equal, then the two dictionaries' contents are equal.
Dictionary<K, V> dictionaryA, dictionaryB;
bool areDictionaryContentsEqual = new HashSet<K>(dictionaryA.Keys).SetEquals(dictionaryB.Keys);
Comparing collections' contents:
To compare two ICollection<T> objects, we need to check:
If they are of the same length.
If every T value that appears in the first collection appears an equal number of times in the second.
public static bool AreCollectionContentsEqual<T>(ICollection<T> collectionA, ICollection<T> collectionB)
where T : notnull
{
if (collectionA.Count != collectionB.Count)
{
return false;
}
Dictionary<T, int> countByValueDictionary = new(collectionA.Count);
foreach(T item in collectionA)
{
countByValueDictionary[item] = countByValueDictionary.TryGetValue(item, out int count)
? count + 1
: 1;
}
foreach (T item in collectionB)
{
if (!countByValueDictionary.TryGetValue(item, out int count) || count < 1)
{
return false;
}
countByValueDictionary[item] = count - 1;
}
return true;
}
These solutions should be optimal since their time and memory complexities are O(n), while the solutions that use ordering/sorting have time and memory complexities greater than O(n).