Reputation: 81
This is kind-of related to this question, on how to merge two dictionaries in C#. An elegant Linq solution is presented, which is cool.
However, that question relates to Dictionary<Object1, Object2>
, whereas I have a dictionary where the value is a Dictionary<string, Object>
.
I am looking for a solution for merging tow Dictionary<string, Dictionary<string, Object>>
, with the following requirements:
For each dictionary I think a grouping by KEY can be part of the solution but after ...
internal static Dictionary<string, Dictionary<string, object>> OperationDic(Dictionary<string, Dictionary<string, object>> a, Dictionary<string, Dictionary<string, object>> b, string operation)`
{
switch (operation)
{
case "+":
var result = a.Concat(b).GroupBy(d => d.Key).ToDictionary (d => d.Key, d => d.First().Value);
return result;
default:
throw new Exception("Fail ...");
}
}
Upvotes: 3
Views: 1420
Reputation: 3123
The first question you should ask yourself: What type does the result of merging two dictionaries have? How can values be merged together if they share the same key?
It could be something like this:
public static Dictionary<TKey, IEnumerable<TValue>> Merge<TKey, TValue>(this IDictionary<TKey, TValue> this_, IDictionary<TKey, TValue> other)
{
return this_.Concat(other). // IEnumerable<KeyValuePair<TKey, TValue>>
GroupBy(kvp => kvp.Key). // grouped by the keys
ToDictionary(grp => grp.Key, grp => grp.Select(kvp => kvp.Value).Distinct());
}
So your two dictionaries of type Dictionary<string, Dictionary<string, object>>
will go to a Dictionary<string, IEnumerable<Dictionary<string, object>>>
.
However, your values are dictionaries so you might want to merge them:
public static Dictionary<TKey, IEnumerable<TValue>> Flatten<TKey, TValue>(IEnumerable<Dictionary<TKey, TValue>> dictionaries)
{
return dictionaries.SelectMany(d => d.Keys).Distinct(). // IEnumerable<TKey> containing all the keys
ToDictionary(key => key,
key => dictionaries.Where(d => d.ContainsKey(key)). // find Dictionaries that contain the key
Select(d => d.First(kvp => kvp.Key.Equals(key))). // select that key (KeyValuePair<TKey, TValue>)
Select(kvp => kvp.Value)); // and the value
}
This takes an IEnumerable<Dictionary<string, object>>
and transforms it into a Dictionary<string, IEnumerable<object>>
. You can now call this method for each value of the dictionary that Merge
produced.
The calls would be:
Dictionary<string, IEnumerable<Dictionary<string, object>>> result1 = dic1.Merge(dic2);
Dictionary<string, Dictionary<string, IEnumerable<object>>> result2 = dic1.Merge(dic2).ToDictionary(kvp => kvp.Key, kvp => Flatten(kvp.Value));
Upvotes: 0
Reputation: 81
internal static Dictionary<string, Dictionary<string, object>> OperationDic(Dictionary<string, Dictionary<string, object>> a, Dictionary<string, Dictionary<string, object>> b, string operation)
{
var result = new Dictionary<string, Dictionary<string, object>>(a);
switch (operation)
{
case "+":
// now check to see if we can add stuff from b
foreach (var entryOuter in b)
{
Dictionary<string, object> existingValue;
if (result.TryGetValue(entryOuter.Key, out existingValue))
{
Dictionary<string, object> Value = entryOuter.Value;
result[entryOuter.Key] = existingValue.Concat(Value).GroupBy(d => d.Key).ToDictionary(d => d.Key, d => d.First().Value);
}
else
{
// new entry
result.Add(entryOuter.Key, entryOuter.Value);
}
}
return result;
default:
throw new Exception("FAIL ...");
}
}
Upvotes: 0
Reputation: 61952
It's not very clear to me what you want. This tries to merge the two dictionaries:
// first copy everything from a
var result = new Dictionary<string, Dictionary<string, object>>(a);
// now check to see if we can add stuff from b
foreach (var entryOuter in b)
{
Dictionary<string, object> existingValue;
if (result.TryGetValue(entryOuter.Key, out existingValue))
{
// there's already an entry, see if we can add to it
foreach (var entryInner in entryOuter.Value)
{
if (existingValue.ContainsKey(entryInner.Key))
throw new Exception("How can I merge two objects? Giving up.");
existingValue.Add(entryInner.Key, entryInner.Value);
}
}
else
{
// new entry
result.Add(entryOuter.Key, entryOuter.Value);
}
}
return result;
You might want to add checks for null
. a
, b
, and existingValue
(when it exists) may be null
.
Upvotes: 1
Reputation: 1
try this
var result = a.Concat(b).GroupBy(c => c.Key).ToDictionary>(
Upvotes: 0