".Add" on Dictionary with a list as value - c#

I've been struggling to Google this question as I can't get the wording quite right (hence the title).
The gist is why do one of the below work, is there a shorthand for test3:
var test1 = new Dictionary<string, int>();
test1["Derp"] = 10; // Success
var test2 = new Dictionary<string, List<int>>();
test2["Derp"].Add(10); // Fail
var test3 = new Dictionary<string, List<int>>();
test3["Derp"] = new List<int>();
test3["Derp"].Add(10); // Success
A scenario I'm coming across often is similar to the below (this is a very basic example):
var names = new List<string>() { "Jim", "Fred", "Fred", "Dave", "Jim", "Jim", "Jim" };
var nameCounts = new Dictionary<string, int>();
foreach(var name in names)
{
if (!nameCounts.ContainsKey(name))
nameCounts.Add(name, 0);
nameCounts[name]++;
}
In other words - is there a way to skip the "ContainsKey" check, and go straight to adding to my list (and key automatically)?
Edit: to be clear, I hadn't used the below as in my real-life situation, it isn't quite as simple (unfortunately!)
var nameCounts = names.GroupBy(x => x)
.ToDictionary(x => x.Key, x => x.Count());

Perl calls this auto-vivification, and I use some extensions to Dictionary to implement various forms, you would need the one that uses a lambda to generate the initial values:
//***
// Enhanced Dictionary that auto-creates missing values with seed lambda
// ala auto-vivification in Perl
//***
public class SeedDictionary<TKey, TValue> : Dictionary<TKey, TValue> {
Func<TValue> seedFn;
public SeedDictionary(Func<TValue> pSeedFn) : base() {
seedFn = pSeedFn;
}
public SeedDictionary(Func<TValue> pSeedFn, IDictionary<TKey, TValue> d) : base() {
seedFn = pSeedFn;
foreach (var kvp in d)
Add(kvp.Key, kvp.Value);
}
public new TValue this[TKey key]
{
get
{
if (!TryGetValue(key, out var val))
base[key] = (val = seedFn());
return val;
}
set => base[key] = value;
}
}
So then you could do test2 like so:
var test2 = new SeedDictionary<string, List<int>>(() => new List<int>());
test2["Derp"].Add(10); // works
For your name counts example, you could use the version that auto-creates the default value for the value type:
//***
// Enhanced Dictionary that auto-creates missing values as default
// ala auto-vivification in Perl
//***
public class AutoDictionary<TKey, TValue> : Dictionary<TKey, TValue> {
public AutoDictionary() : base() { }
public AutoDictionary(IDictionary<TKey, TValue> d) : base() {
foreach (var kvp in d)
Add(kvp.Key, kvp.Value);
}
public new TValue this[TKey key]
{
get
{
if (!TryGetValue(key, out var val))
base[key] = val;
return val;
}
set => base[key] = value;
}
}

Another way you can do this (among many), is a little extension method (cutesy of Jon Skeet here)
public static TValue GetOrCreate<TKey, TValue>(this IDictionary<TKey, TValue> dictionary,TKey key) where TValue : new()
{
TValue ret;
if (!dictionary.TryGetValue(key, out ret))
{
ret = new TValue();
dictionary[key] = ret;
}
return ret;
}
Usage
strong textvar test2 = new Dictionary<string, List<int>>();
var myNewList = test2.GetOrCreate("Derp");
myNewList.Add(10);
// or
var test2 = new Dictionary<string, List<int>>();
test2.GetOrCreate("Derp").Add(10); // winning!
Note : In all my early morning pep, i actually didn't look at this question, Eric Lippert is on the money in the comments, this can be simply done via a GroupBy and a projection to a dictionary with ToDictionary without all the extra fluff of extension methods and classes
Cutesy of Eric Lippert
// Count occurrences of names in a list
var nameCounts = names.GroupBy(x => x)
.ToDictionary(x => x.Key, x => x.Count());
Additional Resources
Enumerable.GroupBy Method
Groups the elements of a sequence.
Enumerable.ToDictionary Method
Creates a Dictionary<TKey,TValue> from an IEnumerable<T>.

I usually do something like this:
TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key)
where TValue : new()
=> dict.TryGetValue(key, out TValue val) ? val : dict[key] = new TValue();
Edit: Another way is:
TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key)
where TValue : new()
=> dict.ContainsKey(key) ? dict[key] : dict[key] = new TValue();
I'm not sure if this is as performant, but it works on older C# versions, where my first example doesn't.

Alternative with C# 7 out variable :
foreach(var name in names)
{
nameCounts[name] = nameCounts.TryGetValue(name, out var count) ? count + 1 : 1;
}

Related

C# sort a dictionary against a string list?

I have the following list (ignore the LST ==> part):
LST ==>Username
LST ==>Password
LST ==>SampleRequestValue
LST ==>SampleComplexRequest
LST ==>SampleComplexRequest.SampleTestBValue
LST ==>SampleComplexRequest.SampleTestAValue
and the following Key List from a dictionary (ignore the DICT ==> part):
DICT ==>Password
DICT ==>Username
DICT ==>SampleRequestValue
DICT ==>SampleComplexRequest.SampleTestAValue
DICT ==>SampleComplexRequest.SampleTestBValue
I want the dictionary sorted in the order of the list (i.e. Username before Password).
Saw a few samples on SO of sorta / kinda / not really examples for this... but not really a similar scenario. Also want it to be as fast as possible rather then brute forcing it.
LST may have more items then DICT. I only care about sorting DICT. DICT will always have a matching entry in LST. I just want the DICT by LST order.
Another way to do this would be to write a small custom comparer class that uses a list to determine comparison values:
public class ListComparer : IComparer<string>
{
public List<string> ComparisonList { get; set; }
public ListComparer(List<string> comparisonList)
{
ComparisonList = comparisonList;
}
public int Compare(string x, string y)
{
if (ComparisonList == null || !ComparisonList.Contains(x))
return 1;
if (ComparisonList.Contains(y))
return ComparisonList.IndexOf(x).CompareTo(ComparisonList.IndexOf(y));
return -1;
}
}
Then you can pass this to the constructor of a SortedDictionary, which will then use it each time an item is added to the dictionary. This way you don't have to call OrderBy on the dictionary every time new values are added (which also has the negative side-effect of creating a whole new dictionary each time).
Here's a code sample that may help. Notice that we add "Password" first, then "Username", but when we output the items, they are in the expected order:
static void Main()
{
var comparisonList = new List<string>
{
"Username",
"Password",
"SampleRequestValue",
"SampleComplexRequest",
"SampleComplexRequest.SampleTestBValue",
"SampleComplexRequest.SampleTestAValue",
};
// Add items in an "unorderd" order
var items = new SortedDictionary<string, string>(new ListComparer(comparisonList))
{
{"Password", "LetMeIn"},
{"Username", "JohnDoe"}
};
foreach (var item in items)
{
Console.WriteLine($"{item.Key} = {item.Value}");
}
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output
I just saw that you don't have control over the initial dictionary, but are willing to create a new one. In that case, you can simply use the overload constructor that takes in a dictionary and a comparer, and it will be automatically sorted on your list:
var sortedItems = new SortedDictionary<string, string>(
originalDictionary, new ListComparer(comparisonList));
Using LINQ this is pretty easy.
First, setup a Dictionary<string,int> to represent your desired sort order:
var orderList = new[] { "Username", "Password", "SampleRequestValue", "SampleComplexRequest", "SampleComplexRequest.SampleTestBValue", "SampleComplexRequest.SampleTestAValue" }
.ToList();
var sortOrder = orderList
.Select((s, p) => new { s, p })
.ToDictionary(sp => sp.s, sp => sp.p);
Then you can sort the DictionaryEntrys from the OrderedDictionary:
var ans = src.Cast<DictionaryEntry>().OrderBy(de => sortOrder[(string)de.Key]);
If you want the answer an an OrderedDictionary, you can convert back using an extension method:
public static class IEnumerableExt {
public static OrderedDictionary ToOrderedDictionary<TKey,TValue,TObj>(this IEnumerable<TObj> src, Func<TObj,TKey> keyFn, Func<TObj, TValue> valueFn) {
var ans = new OrderedDictionary();
foreach (var s in src)
ans.Add(keyFn(s), valueFn(s));
return ans;
}
}
Now just use the extension method:
var odans = ans.ToOrderedDictionary(s => s.Key, s => s.Value);
Just use the OrderBy method :
var SortedDic = dic.OrderBy(o => lst.IndexOf(o.Key));
Here are three extension methods that will do what you want in different ways.
They are used like this (KeySortItems and ValueSortItems are different List<string> lists:
DictionaryItems.ListOrderByKey(KeySortItems)
DictionaryItems.ListOrderByValue(ValueSortItems)
DictionaryItems.ListOrderBy(KeySortItems, (kv, value) => kv.Key.Equals(value))
public static IEnumerable<KeyValuePair<TKey, TValue>> ListOrderByKey<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, List<TValue> list)
{
foreach (var value in list)
foreach (var kv in dictionary)
if (kv.Key.Equals(value))
{
yield return kv;
break;
}
}
public static IEnumerable<KeyValuePair<TKey, TValue>> ListOrderByValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, List<TValue> list)
{
foreach (var value in list)
foreach (var kv in dictionary)
if (kv.Value.Equals(value))
yield return kv;
}
public static IEnumerable<KeyValuePair<TKey, TValue>> ListOrderBy<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, List<TValue> list, Func<KeyValuePair<TKey, TValue>, TValue, bool> func)
{
foreach (var value in list)
foreach (var kv in dictionary)
if (func.Invoke(kv, value))
yield return kv;
}
Copy and paste console app.
using System;
using System.Collections.Generic;
public class Program
{
public static List<string> KeySortItems { get; set; } = new List<string>()
{
"Username",
"Password",
"Item not in Dictionary",
"SampleRequestValue",
"SampleComplexRequest"
};
public static List<string> ValueSortItems { get; set; } = new List<string>()
{
"Mathew",
"1234",
"Item not in Dictionary",
"Sample Request",
"Something Complex"
};
public static Dictionary<string, string> DictionaryItems { get; set; } = new Dictionary<string, string>()
{
["Password"] = "1234",
["Username"] = "Mathew",
["SampleComplexRequest"] = "Something Complex",
["SampleRequestValue"] = "Sample Request"
};
public static void Main()
{
Console.WriteLine("Original Dictionary");
foreach (var kv in DictionaryItems)
{
Console.WriteLine($"{kv.Key} : { kv.Value}");
}
Console.WriteLine("\nSorted by Key");
foreach (var kv in DictionaryItems.ListOrderByKey(KeySortItems))
{
Console.WriteLine($"{kv.Key} : { kv.Value}");
}
Console.WriteLine("\nSorted by Value");
foreach (var kv in DictionaryItems.ListOrderByValue(ValueSortItems))
{
Console.WriteLine($"{kv.Key} : { kv.Value}");
}
Console.WriteLine("\nSorted by Keys via func");
foreach (var kv in DictionaryItems.ListOrderBy(KeySortItems, (kv, value) => kv.Key.Equals(value)))
{
Console.WriteLine($"{kv.Key} : { kv.Value}");
}
Console.ReadKey();
}
}
public static class Extensions
{
public static IEnumerable<KeyValuePair<TKey, TValue>> ListOrderByKey<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, List<TValue> list)
{
foreach (var value in list)
foreach (var kv in dictionary)
if (kv.Key.Equals(value))
yield return kv;
}
public static IEnumerable<KeyValuePair<TKey, TValue>> ListOrderByValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, List<TValue> list)
{
foreach (var value in list)
foreach (var kv in dictionary)
if (kv.Value.Equals(value))
yield return kv;
}
public static IEnumerable<KeyValuePair<TKey, TValue>> ListOrderBy<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, List<TValue> list, Func<KeyValuePair<TKey, TValue>, TValue, bool> func)
{
foreach (var value in list)
foreach (var kv in dictionary)
if (func.Invoke(kv, value))
yield return kv;
}
}
//OUTPUT
//Original Dictionary
//Password : 1234
//Username : Mathew
//SampleComplexRequest : Something Complex
//SampleRequestValue : Sample Request
//Sorted by Key
//Username : Mathew
//Password : 1234
//SampleRequestValue : Sample Request
//SampleComplexRequest : Something Complex
//Sorted by Value
//Username : Mathew
//Password : 1234
//SampleRequestValue : Sample Request
//SampleComplexRequest : Something Complex
//Sorted by Keys via func
//Username : Mathew
//Password : 1234
//SampleRequestValue : Sample Request
//SampleComplexRequest : Something Complex

Two-value dictionary which returns any of the value for a specific key

I need to create a dictionary that has 2 values per key, and it must return one of the 2 values with the same probability.
Example:
myDicry
{
key = "A", value1=15, value2=56;
}
int firstCall = myDicry["A"]; // = 15
int secondCall = myDicry["A"]; // = 56
It would be possible to write an IDictionary<TKey, TValue> implementation that behaved in this manner, but that would not be a good idea: most people would find a non-deterministic indexer for a collection-class very unintuitive.
Instead, I suggest you make this the responsibility of the value for a key, rather than the Dictionary itself. One option would be to write a custom-type that is capable of picking from a set of possibilities with equal probability. For example:
public class UnbiasedRandomPicker<T>
{
private readonly Random _rand = new Random();
private readonly T[] _possibilities;
public UnbiasedRandomPicker(params T[] possibilities)
{
// argument validation omitted
_possibilities = possibilities;
}
public T GetRandomValue()
{
return _possibilities[_rand.Next(_possibilities.Length)];
}
}
You could then use the dictionary like this:
var dict = new Dictionary<string, UnbiasedRandomPicker<int>>
{
{"A", new UnbiasedRandomPicker<int>(15, 56)},
{"B", new UnbiasedRandomPicker<int>(25, 13)}
};
int randomValueFromA = dict["A"].GetRandomValue();
There's nothing built into the framework to do this, but you'd probably want to implement it by creating a "wrapper" type which had a Dictionary<TKey, Tuple<TValue, TValue>>. You'd then write an indexer to choose appropriately between the two values.
I would actually just implement this in a class that uses a Dictionary<TKey, TValue[]> internally. That way you could even implement the type to have a variable number of values per key.
Like:
class RandomDictionary<TKey, TValue>
{
Dictionary<TKey, TValue[]> m_dict;
Random m_random;
public RandomDictionary()
{
m_dict = new Dictionary<TKey, TValue[]>();
m_random = new Random();
}
public TValue this[TKey key]
{
get
{
TValue[] values = m_dict[key];
return values[m_random.Next(0, values.Length)];
}
}
public void Define(TKey key, params TValue[] values)
{
m_dict[key] = new TValue[values.Length];
Array.Copy(values, m_dict[key], values.Length);
}
public bool TryGetValue(TKey key, out TValue value)
{
TValue[] values;
if (!m_dict.TryGetValue(key, out values))
{
value = default(TValue);
return false;
}
value = values[m_random.Next(0, values.Length)];
return true;
}
}
Use Tuple as dictionary value type.
IDictionary<string, Tuple<int, int>> doubleDictionary = new Dictionary<string, Tuple<int, int>>();
// ...
int secondValue = doubleDictionary["A"].Item2;
You could also write an extension method for the dictionary, so you could create something like this:
IDictionary<string, Tuple<int, int>> doubleDictionary = new Dictionary<string, Tuple<int, int>>();
doubleDictionary.GetRandomValueForKey("A");
Then you can use this with any dictionary.
public static void GetRandomValueForKey(this Dictionary<string, Tuple<int, int>> dict,
string key)
{
... Code to return the value
}
^^ that was written off the top of my head, so please excuse me if this is slightly wrong.
This below code will solve the dictionary part of the problem and make the randomization customizable so that you can apply a level so pseudo-randomness that suits your needs. (or simply hard code it instead of the use of a functor)
public class DoubleDictionary<K, T> : IEnumerable<KeyValuePair<K, T>>
{
private readonly Dictionary<K, Tuple<T, T>> _dictionary = new Dictionary<K, Tuple<T, T>>();
private readonly Func<bool> _getFirst;
public DoubleDictionary(Func<bool> GetFirst) {
_getFirst = GetFirst;
}
public void Add(K Key, Tuple<T, T> Value) {
_dictionary.Add(Key, Value);
}
public T this[K index] {
get {
Tuple<T, T> pair = _dictionary[index];
return GetValue(pair);
}
}
private T GetValue(Tuple<T, T> Pair) {
return _getFirst() ? Pair.Item1 : Pair.Item2;
}
public IEnumerable<K> Keys {
get {
return _dictionary.Keys;
}
}
public IEnumerable<T> Values {
get {
foreach (var pair in _dictionary.Values) {
yield return GetValue(pair);
}
}
}
IEnumerator<KeyValuePair<K, T>> IEnumerable<KeyValuePair<K, T>>.GetEnumerator() {
foreach (var pair in _dictionary) {
yield return new KeyValuePair<K, T>(pair.Key, GetValue(pair.Value));
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return ((IEnumerable<KeyValuePair<K, T>>)this).GetEnumerator();
}
}

Elegant way to go from list of objects to dictionary with two of the properties

i seem to write this code over and over again and wanted to see if there was a better way of doing it more generically.
I start out with a list of Foo objects
Foo[] foos = GenerateFoos();
I think want to create a dictionary where the key and value are both properties of Foo
for example:
Dictionary<string, string> fooDict = new Dictionary<string, string>():
foreach (Foo foo in foos)
{
fooDict[foo.Name] = foo.StreetAddress;
}
is there anyway of writing this code generically as it seems like a basic template where there is an array of objects, a key property a value property and a dictionary.
Any suggestions?
I am using VS 2005 (C#, 2.0)
With LINQ:
var fooDict = foos.ToDictionary(x=>x.Name,x=>x.StreetAddress);
(and yes, fooDict is Dictionary<string, string>)
edit to show the pain in VS2005:
Dictionary<string, string> fooDict =
Program.ToDictionary<Foo, string, string>(foos,
delegate(Foo foo) { return foo.Name; },
delegate(Foo foo) { return foo.StreetAddress; });
where you have (in Program):
public static Dictionary<TKey, TValue> ToDictionary<TSource, TKey, TValue>(
IEnumerable<TSource> items,
Converter<TSource, TKey> keySelector,
Converter<TSource, TValue> valueSelector)
{
Dictionary<TKey, TValue> result = new Dictionary<TKey, TValue>();
foreach (TSource item in items)
{
result.Add(keySelector(item), valueSelector(item));
}
return result;
}
If you are using framework 3.5, you can use the ToDictionary extension:
Dictionary<string, string> fooDict = foos.ToDictionary(f => f.Name, f => f.StreetAddress);
For framework 2.0, the code is pretty much as simple as it can be.
You can improve the performance a bit by specifying the capacity for the dictionary when you create it, so that it doesn't have to do any reallocations while you fill it:
Dictionary<string, string> fooDict = new Dictionary<string, string>(foos.Count):
Without LINQ, no, there's no built-in helpers for this. You could write one though:
// I forget if you need this delegate definition -- this may be already defined in .NET 2.0
public delegate R Func<T,R>(T obj);
public static Dictionary<K,V> BuildDictionary<T,K,V>(IEnumerable<T> objs, Func<T,K> kf, Func<T,V> vf)
{
Dictionary<K,V> d = new Dictionary<K,V>();
foreach (T obj in objs)
{
d[kf(obj)] = vf(obj);
}
return d;
}
Dictionary<string, string> fooDict = BuildDictionary(foos, new Func<Foo,string>(delegate(Foo foo) { return foo.Name; }), new Func<Foo,string>(delegate(Foo foo) { return foo.StreetAddress; }));
It doesn't look nearly as elegant as the LINQ-based answers, does it...
Here's a solution that's .net 2.0 compatible that uses System.Web.UI.Databinder to do the reflection on the property name - you lose compile-time type checking.
public static Dictionary<string, string> ToDictionary<T>(List<T> list, string keyName, string valueName)
{
Dictionary<string, string> outputDictionary = new Dictionary<string, string>();
foreach (T item in list)
{
string key = Eval<T, string>(item, keyName);
string value = Eval<T, string>(item, valueName);
output[key] = value;
}
return outputDictionary;
}
public static TOut Eval<TIn, TOut>(TIn source, string propertyName)
{
object o = DataBinder.GetPropertyValue(source, propertyName);
if (o is TOut)
return (TOut)o;
return default(TOut);
}
You would call as follows:
Dictionary<string, string> fooDict = ToDictionary(foos, "Name", "StreetAddress");

How do I convert from a Dictionary to a SortedDictionary using LINQ in C#?

How to convert a Dictionary to a SortedDictionary?
In addition to general conversion (preserving types of key and values) I'm interested in swapping the keys and values as part of the conversion: have a Dictionary<string, double> and I want to convert it to a SortedDictionary<double, string>.
How do I do this using LINQ extension methods in C# 3.0?
Why use LINQ? There is a constructor for this:
new SortedDictionary<int, string>(existing);
You could add a ToSortedDictionary - but I wouldn't bother...
Note: this is an answer to the title of the question (convert a Dictionary to a SortedDictionary for the same types, if you need additional step that OP is looking for - swap key and values in the process - as shown in the updated problem, see this answer.
No LINQ is needed. SortedDictionary has a constructor to do the conversion.
public SortedDictionary<TKey,TValue> Convert<TKey,TValue>(Dictionary<TKey,TValue> map) {
return new SortedDictionary<TKey,TValue>(map);
}
This answer addresses conversion with swapping keys and values in the process.
It seems as though you are asking for an elegant way to take a Dictionary<TKey,TValue> and turn that into a SortedDictionary<TValue,TKey> (note that the value of the Dictionary is now the key of the SortedDictionary).
You could create an extension method that swaps keys and values of the dictionary into another dictionary:
static class Extensions
{
public static Dictionary<TValue, TKey>
AsInverted<TKey, TValue>(this Dictionary<TKey, TValue> source)
{
var inverted = new Dictionary<TValue, TKey>();
foreach (KeyValuePair<TKey, TValue> key in source)
inverted.Add(key.Value, key.Key);
return inverted;
}
}
And your application code would use that helper method to swap keys and values and use regular constructor of SortedDictionary like this:
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
static void Main()
{
var dict = new Dictionary<String, Double>();
dict.Add("four", 4);
dict.Add("three", 3);
dict.Add("two", 2);
dict.Add("five", 5);
dict.Add("one", 1);
var sortedDict = new SortedDictionary<Double, String>(dict.AsInverted());
}
}
You don't need LINQ, just some nifty extension methods:
public static IDictionary<TKey, TValue> Sort<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
{
if(dictionary == null)
{
throw new ArgumentNullException("dictionary");
}
return new SortedDictionary<TKey, TValue>(dictionary);
}
public static IDictionary<TKey, TValue> Sort<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, IComparer<TKey> comparer)
{
if(dictionary == null)
{
throw new ArgumentNullException("dictionary");
}
if(comparer == null)
{
throw new ArgumentNullException("comparer");
}
return new SortedDictionary<TKey, TValue>(dictionary, comparer);
}
Example usage:
var dictionary = new Dictionary<int, string>
{
{ 1, "one" },
{ 2, "two" },
{ 0, "zero" }
};
foreach(var pair in dictionary.Sort())
{
Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
}
// 0: zero
// 1: one
// 2: two
Inversion using ToDictionary:
public static IDictionary<TValue, TKey> Invert<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
{
if(dictionary == null)
{
throw new ArgumentNullException("dictionary");
}
return dictionary.ToDictionary(pair => pair.Value, pair => pair.Key);
}
Example usage:
var dictionary = new Dictionary<string, int>
{
{ "zero", 0 },
{ "one", 1 },
{ "two", 2 }
};
foreach(var pair in dictionary.Invert())
{
Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
}
// 0: zero
// 1: one
// 2: two
Example of inverting and sorting (see my other answer for the definition of Sort):
var dictionary = new Dictionary<string, int>
{
{ "one", 1 },
{ "two", 2 },
{ "zero", 0 }
};
foreach(var pair in dictionary.Invert().Sort())
{
Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
}
// 0: zero
// 1: one
// 2: two

Merging dictionaries in C#

What's the best way to merge 2 or more dictionaries (Dictionary<TKey, TValue>) in C#?
(3.0 features like LINQ are fine).
I'm thinking of a method signature along the lines of:
public static Dictionary<TKey,TValue>
Merge<TKey,TValue>(Dictionary<TKey,TValue>[] dictionaries);
or
public static Dictionary<TKey,TValue>
Merge<TKey,TValue>(IEnumerable<Dictionary<TKey,TValue>> dictionaries);
Regarding the handling of duplicate keys: In case of collision, it doesn't matter which value is saved to the dictionary as long as it's consistent.
This partly depends on what you want to happen if you run into duplicates. For instance, you could do:
var result = dictionaries.SelectMany(dict => dict)
.ToDictionary(pair => pair.Key, pair => pair.Value);
That will throw an exception if you get any duplicate keys.
EDIT: If you use ToLookup then you'll get a lookup which can have multiple values per key. You could then convert that to a dictionary:
var result = dictionaries.SelectMany(dict => dict)
.ToLookup(pair => pair.Key, pair => pair.Value)
.ToDictionary(group => group.Key, group => group.First());
It's a bit ugly - and inefficient - but it's the quickest way to do it in terms of code. (I haven't tested it, admittedly.)
You could write your own ToDictionary2 extension method of course (with a better name, but I don't have time to think of one now) - it's not terribly hard to do, just overwriting (or ignoring) duplicate keys. The important bit (to my mind) is using SelectMany, and realising that a dictionary supports iteration over its key/value pairs.
I would do it like this:
dictionaryFrom.ToList().ForEach(x => dictionaryTo.Add(x.Key, x.Value));
Simple and easy. According to this blog post it's even faster than most loops as its underlying implementation accesses elements by index rather than enumerator (see this answer).
It will of course throw an exception if there are duplicates, so you'll have to check before merging.
This doesn't explode if there are multiple keys ("righter" keys replace "lefter" keys), can merge a number of dictionaries (if desired) and preserves the type (with the restriction that it requires a meaningful default public constructor):
public static class DictionaryExtensions
{
// Works in C#3/VS2008:
// Returns a new dictionary of this ... others merged leftward.
// Keeps the type of 'this', which must be default-instantiable.
// Example:
// result = map.MergeLeft(other1, other2, ...)
public static T MergeLeft<T,K,V>(this T me, params IDictionary<K,V>[] others)
where T : IDictionary<K,V>, new()
{
T newMap = new T();
foreach (IDictionary<K,V> src in
(new List<IDictionary<K,V>> { me }).Concat(others)) {
// ^-- echk. Not quite there type-system.
foreach (KeyValuePair<K,V> p in src) {
newMap[p.Key] = p.Value;
}
}
return newMap;
}
}
The trivial solution would be:
using System.Collections.Generic;
...
public static Dictionary<TKey, TValue>
Merge<TKey,TValue>(IEnumerable<Dictionary<TKey, TValue>> dictionaries)
{
var result = new Dictionary<TKey, TValue>();
foreach (var dict in dictionaries)
foreach (var x in dict)
result[x.Key] = x.Value;
return result;
}
Try the following
static Dictionary<TKey, TValue>
Merge<TKey, TValue>(this IEnumerable<Dictionary<TKey, TValue>> enumerable)
{
return enumerable.SelectMany(x => x).ToDictionary(x => x.Key, y => y.Value);
}
I'm very late to the party and perhaps missing something, but if either there are no duplicate keys or, as the OP says, "In case of collision, it doesn't matter which value is saved to the dict as long as it's consistent," what's wrong with this one (merging D2 into D1)?
foreach (KeyValuePair<string,int> item in D2)
{
D1[item.Key] = item.Value;
}
It seems simple enough, maybe too simple, I wonder if I'm missing something. This is what I'm using in some code where I know there are no duplicate keys. I'm still in testing, though, so I'd love to know now if I'm overlooking something, instead of finding out later.
Dictionary<String, String> allTables = new Dictionary<String, String>();
allTables = tables1.Union(tables2).ToDictionary(pair => pair.Key, pair => pair.Value);
Here is a helper function I use:
using System.Collections.Generic;
namespace HelperMethods
{
public static class MergeDictionaries
{
public static void Merge<TKey, TValue>(this IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
{
if (second == null || first == null) return;
foreach (var item in second)
if (!first.ContainsKey(item.Key))
first.Add(item.Key, item.Value);
}
}
}
The following works for me. If there are duplicates, it will use dictA's value.
public static IDictionary<TKey, TValue> Merge<TKey, TValue>(this IDictionary<TKey, TValue> dictA, IDictionary<TKey, TValue> dictB)
where TValue : class
{
return dictA.Keys.Union(dictB.Keys).ToDictionary(k => k, k => dictA.ContainsKey(k) ? dictA[k] : dictB[k]);
}
Option 1 : This depends on what you want to happen if you are sure that you don't have duplicate key in both dictionaries. than you could do:
var result = dictionary1.Union(dictionary2).ToDictionary(k => k.Key, v => v.Value)
Note : This will throw error if you get any duplicate keys in dictionaries.
Option 2 : If you can have duplicate key then you'll have to handle duplicate key with the using of where clause.
var result = dictionary1.Union(dictionary2.Where(k => !dictionary1.ContainsKey(k.Key))).ToDictionary(k => k.Key, v => v.Value)
Note : It will not get duplicate key. if there will be any duplicate key than it will get dictionary1's key.
Option 3 : If you want to use ToLookup. then you will get a lookup which can have multiple values per key. You could convert that lookup to a dictionary:
var result = dictionaries.SelectMany(dict => dict)
.ToLookup(pair => pair.Key, pair => pair.Value)
.ToDictionary(group => group.Key, group => group.First());
Based on the answers above, but adding a Func-parameter to let the caller handle the duplicates:
public static Dictionary<TKey, TValue> Merge<TKey, TValue>(this IEnumerable<Dictionary<TKey, TValue>> dicts,
Func<IGrouping<TKey, TValue>, TValue> resolveDuplicates)
{
if (resolveDuplicates == null)
resolveDuplicates = new Func<IGrouping<TKey, TValue>, TValue>(group => group.First());
return dicts.SelectMany<Dictionary<TKey, TValue>, KeyValuePair<TKey, TValue>>(dict => dict)
.ToLookup(pair => pair.Key, pair => pair.Value)
.ToDictionary(group => group.Key, group => resolveDuplicates(group));
}
How about adding a params overload?
Also, you should type them as IDictionary for maximum flexibility.
public static IDictionary<TKey, TValue> Merge<TKey, TValue>(IEnumerable<IDictionary<TKey, TValue>> dictionaries)
{
// ...
}
public static IDictionary<TKey, TValue> Merge<TKey, TValue>(params IDictionary<TKey, TValue>[] dictionaries)
{
return Merge((IEnumerable<TKey, TValue>) dictionaries);
}
The party's pretty much dead now, but here's an "improved" version of user166390 that made its way into my extension library.
Apart from some details, I added a delegate to calculate the merged value.
/// <summary>
/// Merges a dictionary against an array of other dictionaries.
/// </summary>
/// <typeparam name="TResult">The type of the resulting dictionary.</typeparam>
/// <typeparam name="TKey">The type of the key in the resulting dictionary.</typeparam>
/// <typeparam name="TValue">The type of the value in the resulting dictionary.</typeparam>
/// <param name="source">The source dictionary.</param>
/// <param name="mergeBehavior">A delegate returning the merged value. (Parameters in order: The current key, The current value, The previous value)</param>
/// <param name="mergers">Dictionaries to merge against.</param>
/// <returns>The merged dictionary.</returns>
public static TResult MergeLeft<TResult, TKey, TValue>(
this TResult source,
Func<TKey, TValue, TValue, TValue> mergeBehavior,
params IDictionary<TKey, TValue>[] mergers)
where TResult : IDictionary<TKey, TValue>, new()
{
var result = new TResult();
var sources = new List<IDictionary<TKey, TValue>> { source }
.Concat(mergers);
foreach (var kv in sources.SelectMany(src => src))
{
TValue previousValue;
result.TryGetValue(kv.Key, out previousValue);
result[kv.Key] = mergeBehavior(kv.Key, kv.Value, previousValue);
}
return result;
}
Considering the performance of dictionary key lookups and deletes since they are hash operations, and considering the wording of the question was best way, I think that below is a perfectly valid approach, and the others are a bit over-complicated, IMHO.
public static void MergeOverwrite<T1, T2>(this IDictionary<T1, T2> dictionary, IDictionary<T1, T2> newElements)
{
if (newElements == null) return;
foreach (var e in newElements)
{
dictionary.Remove(e.Key); //or if you don't want to overwrite do (if !.Contains()
dictionary.Add(e);
}
}
OR if you're working in a multithreaded application and your dictionary needs to be thread safe anyway, you should be doing this:
public static void MergeOverwrite<T1, T2>(this ConcurrentDictionary<T1, T2> dictionary, IDictionary<T1, T2> newElements)
{
if (newElements == null || newElements.Count == 0) return;
foreach (var ne in newElements)
{
dictionary.AddOrUpdate(ne.Key, ne.Value, (key, value) => value);
}
}
You could then wrap this to make it handle an enumeration of dictionaries. Regardless, you're looking at about ~O(3n) (all conditions being perfect), since the .Add() will do an additional, unnecessary but practically free, Contains() behind the scenes. I don't think it gets much better.
If you wanted to limit extra operations on large collections, you should sum up the Count of each dictionary you're about to merge and set the capacity of the the target dictionary to that, which avoids the later cost of resizing. So, end product is something like this...
public static IDictionary<T1, T2> MergeAllOverwrite<T1, T2>(IList<IDictionary<T1, T2>> allDictionaries)
{
var initSize = allDictionaries.Sum(d => d.Count);
var resultDictionary = new Dictionary<T1, T2>(initSize);
allDictionaries.ForEach(resultDictionary.MergeOverwrite);
return resultDictionary;
}
Note that I took in an IList<T> to this method... mostly because if you take in an IEnumerable<T>, you've opened yourself up to multiple enumerations of the same set, which can be very costly if you got your collection of dictionaries from a deferred LINQ statement.
Simplified again from earlier without LINQ and a bool default of non-destructive merge if existing or overwrite entirely if true rather than using an enum. It still suits my own needs without any fancier code ever being required:
using System.Collections.Generic;
using System.Linq;
public static partial class Extensions
{
public static void Merge<K, V>(this IDictionary<K, V> target,
IDictionary<K, V> source,
bool overwrite = false)
{
foreach (KeyValuePair _ in source)
if (overwrite || !target.ContainsKey(_.Key))
target[_.Key] = _.Value;
}
}
Note that if you use an extension method called 'Add', you get to use collection initializers to combine as many dictionaries as needed like this:
public static void Add<K, V>(this Dictionary<K, V> d, Dictionary<K, V> other) {
foreach (var kvp in other)
{
if (!d.ContainsKey(kvp.Key))
{
d.Add(kvp.Key, kvp.Value);
}
}
}
var s0 = new Dictionary<string, string> {
{ "A", "X"}
};
var s1 = new Dictionary<string, string> {
{ "A", "X" },
{ "B", "Y" }
};
// Combine as many dictionaries and key pairs as needed
var a = new Dictionary<string, string> {
s0, s1, s0, s1, s1, { "C", "Z" }
};
using System.Collections.Generic;
using System.Linq;
public static class DictionaryExtensions
{
public enum MergeKind { SkipDuplicates, OverwriteDuplicates }
public static void Merge<K, V>(this IDictionary<K, V> target, IDictionary<K, V> source, MergeKind kind = MergeKind.SkipDuplicates) =>
source.ToList().ForEach(_ => { if (kind == MergeKind.OverwriteDuplicates || !target.ContainsKey(_.Key)) target[_.Key] = _.Value; });
}
You can either skip/ignore (default) or overwrite the duplicates: And Bob's your uncle provided you are not overly fussy about Linq performance but prefer instead concise maintainable code as I do: in which case you can remove the default MergeKind.SkipDuplicates to enforce a choice for the caller and make the developer cognisant of what the results will be!
#Tim: Should be a comment, but comments don't allow for code editing.
Dictionary<string, string> t1 = new Dictionary<string, string>();
t1.Add("a", "aaa");
Dictionary<string, string> t2 = new Dictionary<string, string>();
t2.Add("b", "bee");
Dictionary<string, string> t3 = new Dictionary<string, string>();
t3.Add("c", "cee");
t3.Add("d", "dee");
t3.Add("b", "bee");
Dictionary<string, string> merged = t1.MergeLeft(t2, t2, t3);
Note: I applied the modification by #ANeves to the solution by #Andrew Orsich, so the MergeLeft looks like this now:
public static Dictionary<K, V> MergeLeft<K, V>(this Dictionary<K, V> me, params IDictionary<K, V>[] others)
{
var newMap = new Dictionary<K, V>(me, me.Comparer);
foreach (IDictionary<K, V> src in
(new List<IDictionary<K, V>> { me }).Concat(others))
{
// ^-- echk. Not quite there type-system.
foreach (KeyValuePair<K, V> p in src)
{
newMap[p.Key] = p.Value;
}
}
return newMap;
}
I know this is an old question, but since we now have LINQ you can do it in a single line like this
Dictionary<T1,T2> merged;
Dictionary<T1,T2> mergee;
mergee.ToList().ForEach(kvp => merged.Add(kvp.Key, kvp.Value));
or
mergee.ToList().ForEach(kvp => merged.Append(kvp));
Got scared to see complex answers, being new to C#.
Here are some simple answers.
Merging d1, d2, and so on.. dictionaries and handle any overlapping keys ("b" in below examples):
Example 1
{
// 2 dictionaries, "b" key is common with different values
var d1 = new Dictionary<string, int>() { { "a", 10 }, { "b", 21 } };
var d2 = new Dictionary<string, int>() { { "c", 30 }, { "b", 22 } };
var result1 = d1.Concat(d2).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.First().Value);
// result1 is a=10, b=21, c=30 That is, took the "b" value of the first dictionary
var result2 = d1.Concat(d2).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.Last().Value);
// result2 is a=10, b=22, c=30 That is, took the "b" value of the last dictionary
}
Example 2
{
// 3 dictionaries, "b" key is common with different values
var d1 = new Dictionary<string, int>() { { "a", 10 }, { "b", 21 } };
var d2 = new Dictionary<string, int>() { { "c", 30 }, { "b", 22 } };
var d3 = new Dictionary<string, int>() { { "d", 40 }, { "b", 23 } };
var result1 = d1.Concat(d2).Concat(d3).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.First().Value);
// result1 is a=10, b=21, c=30, d=40 That is, took the "b" value of the first dictionary
var result2 = d1.Concat(d2).Concat(d3).GroupBy(ele => ele.Key).ToDictionary(ele => ele.Key, ele => ele.Last().Value);
// result2 is a=10, b=23, c=30, d=40 That is, took the "b" value of the last dictionary
}
For more complex scenarios, see other answers.
Hope that helped.
A version from #user166390 answer with an added IEqualityComparer parameter to allow for case insensitive key comparison.
public static T MergeLeft<T, K, V>(this T me, params Dictionary<K, V>[] others)
where T : Dictionary<K, V>, new()
{
return me.MergeLeft(me.Comparer, others);
}
public static T MergeLeft<T, K, V>(this T me, IEqualityComparer<K> comparer, params Dictionary<K, V>[] others)
where T : Dictionary<K, V>, new()
{
T newMap = Activator.CreateInstance(typeof(T), new object[] { comparer }) as T;
foreach (Dictionary<K, V> src in
(new List<Dictionary<K, V>> { me }).Concat(others))
{
// ^-- echk. Not quite there type-system.
foreach (KeyValuePair<K, V> p in src)
{
newMap[p.Key] = p.Value;
}
}
return newMap;
}
This is my solution: it behaves like the dict.update() method in python.
public static class DictionaryExtensions
{
public static void Update<K,V>(this IDictionary<K, V> me, IDictionary<K, V> other)
{
foreach (var x in other)
{
me[x.Key] = x.Value;
}
}
}
Merging using an extension method. It does not throw exception when there are duplicate keys, but replaces those keys with keys from the second dictionary.
internal static class DictionaryExtensions
{
public static Dictionary<T1, T2> Merge<T1, T2>(this Dictionary<T1, T2> first, Dictionary<T1, T2> second)
{
if (first == null) throw new ArgumentNullException("first");
if (second == null) throw new ArgumentNullException("second");
var merged = new Dictionary<T1, T2>();
first.ToList().ForEach(kv => merged[kv.Key] = kv.Value);
second.ToList().ForEach(kv => merged[kv.Key] = kv.Value);
return merged;
}
}
Usage:
Dictionary<string, string> merged = first.Merge(second);
public static IDictionary<K, V> AddRange<K, V>(this IDictionary<K, V> one, IDictionary<K, V> two)
{
foreach (var kvp in two)
{
if (one.ContainsKey(kvp.Key))
one[kvp.Key] = two[kvp.Key];
else
one.Add(kvp.Key, kvp.Value);
}
return one;
}
I'd split #orip's simple and non-garbage creating solution to provide a in-place AddAll() in addition to Merge() to handle the simple case of adding one dictionary to another.
using System.Collections.Generic;
...
public static Dictionary<TKey, TValue>
AddAll<TKey,TValue>(Dictionary<TKey, TValue> dest, Dictionary<TKey, TValue> source)
{
foreach (var x in source)
dest[x.Key] = x.Value;
}
public static Dictionary<TKey, TValue>
Merge<TKey,TValue>(IEnumerable<Dictionary<TKey, TValue>> dictionaries)
{
var result = new Dictionary<TKey, TValue>();
foreach (var dict in dictionaries)
result.AddAll(dict);
return result;
}
Merging using an EqualityComparer that maps items for comparison to a different value/type. Here we will map from KeyValuePair (item type when enumerating a dictionary) to Key.
public class MappedEqualityComparer<T,U> : EqualityComparer<T>
{
Func<T,U> _map;
public MappedEqualityComparer(Func<T,U> map)
{
_map = map;
}
public override bool Equals(T x, T y)
{
return EqualityComparer<U>.Default.Equals(_map(x), _map(y));
}
public override int GetHashCode(T obj)
{
return _map(obj).GetHashCode();
}
}
Usage:
// if dictA and dictB are of type Dictionary<int,string>
var dict = dictA.Concat(dictB)
.Distinct(new MappedEqualityComparer<KeyValuePair<int,string>,int>(item => item.Key))
.ToDictionary(item => item.Key, item=> item.Value);
or :
public static IDictionary<TKey, TValue> Merge<TKey, TValue>( IDictionary<TKey, TValue> x, IDictionary<TKey, TValue> y)
{
return x
.Except(x.Join(y, z => z.Key, z => z.Key, (a, b) => a))
.Concat(y)
.ToDictionary(z => z.Key, z => z.Value);
}
the result is a union where for duplicate entries "y" wins.
Try that
namespace Extensions
{
public static class DictionaryExtensions
{
public static Dictionary<T, Y> MergeWith<T, Y>(this Dictionary<T, Y> dictA,
Dictionary<T, Y> dictB)
{
foreach (var item in dictB)
{
if (dictA.ContainsKey(item.Key))
dictA[item.Key] = item.Value;
else
dictA.Add(item.Key, item.Value);
}
return dictA;
}
}
}
When you want to merge two dictionaries
var d1 = new Dictionary<string, string>();
var d2 = new Dictionary<string, string>();
d1.MergeWith(d2);
Based on all the answers on this post, here's the most generic solution I could came up with.
I created 2 versions of the IDictionary.Merge() extension :
Merge<T, U>(sourceLeft, sourceRight)
Merge<T, U>(sourceLeft, sourceRight, Func<U, U, U> mergeExpression)
Where the second is a modified version of the first that lets you specify a lambda expression to handle duplicates like this :
Dictionary<string, object> customAttributes =
HtmlHelper
.AnonymousObjectToHtmlAttributes(htmlAttributes)
.ToDictionary(
ca => ca.Key,
ca => ca.Value
);
Dictionary<string, object> fixedAttributes =
new RouteValueDictionary(
new {
#class = "form-control"
}).ToDictionary(
fa => fa.Key,
fa => fa.Value
);
//appending the html class attributes
IDictionary<string, object> editorAttributes = fixedAttributes.Merge(customAttributes, (leftValue, rightValue) => leftValue + " " + rightValue);
(You can focus on the ToDictionary() and Merge() parts)
And here's the extension class (with 2 versions of the extension that take a collection of IDictionary on the right side):
public static class IDictionaryExtension
{
public static IDictionary<T, U> Merge<T, U>(this IDictionary<T, U> sourceLeft, IDictionary<T, U> sourceRight)
{
IDictionary<T, U> result = new Dictionary<T,U>();
sourceLeft
.Concat(sourceRight)
.ToList()
.ForEach(kvp =>
result[kvp.Key] = kvp.Value
);
return result;
}
public static IDictionary<T, U> Merge<T, U>(this IDictionary<T, U> sourceLeft, IDictionary<T, U> sourceRight, Func<U, U, U> mergeExpression)
{
IDictionary<T, U> result = new Dictionary<T,U>();
//Merge expression example
//(leftValue, rightValue) => leftValue + " " + rightValue;
sourceLeft
.Concat(sourceRight)
.ToList()
.ForEach(kvp =>
result[kvp.Key] =
(!result.ContainsKey(kvp.Key))
? kvp.Value
: mergeExpression(result[kvp.Key], kvp.Value)
);
return result;
}
public static IDictionary<T, U> Merge<T, U>(this IDictionary<T, U> sourceLeft, IEnumerable<IDictionary<T, U>> sourcesRight)
{
IDictionary<T, U> result = new Dictionary<T, U>();
new[] { sourceLeft }
.Concat(sourcesRight)
.ToList()
.ForEach(dic =>
result = result.Merge(dic)
);
return result;
}
public static IDictionary<T, U> Merge<T, U>(this IDictionary<T, U> sourceLeft, IEnumerable<IDictionary<T, U>> sourcesRight, Func<U, U, U> mergeExpression)
{
IDictionary<T, U> result = new Dictionary<T, U>();
new[] { sourceLeft }
.Concat(sourcesRight)
.ToList()
.ForEach(dic =>
result = result.Merge(dic, mergeExpression)
);
return result;
}
}
The mergeExpression let's you easily handle the way you want to merge the items, like addition, division, multiplication or any kind of specific process you desire.
Note that I've not yet tested the collection versions of the extension... they may still require some tuning.
Also, the extension does NOT modify the original dictionaries, you'll have to assign it back if you want to.

Categories

Resources