How to append value for existing key in dictionary in C# - c#

The below code tries to store multiple values for a single key. I have managed to store the value for non-exist key. Can you guid me on how I can append value for existing key?
Dictionary<string,HashSet<string>> container = new Dictionary<string,HashSet<string>>();
foreach(dynamic x in records)
{ if(!container.ContainsKey(x.code))
{
HashSet<string> item = new HashSet<string>();
item.Add(x.name);
container.Add(x.code,item);
}
}

I believe this is what you're looking for?
Dictionary<string, HashSet<string>> container = new Dictionary<string, HashSet<string>>();
HashSet<string> item;
if (!container.ContainsKey(s))
{
item = new HashSet<string>();
container.Add("key1", item);
}
else
{
item = container[s];
}
item.Add("value1");
Note that I'd expect if the dictionary doesn't have key s then you'll want to add the HashSet<string> with same key s, not "key1", but that's up to you.
If indeed the key s should be added you can implement a reusable generic extension method:
public static TValue GetOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, Func<TKey, TValue> newValueFactory)
{
if (!dict.TryGetValue(key, out var value))
{
value = newValueFactory(key);
dict.Add(key, value);
}
return value;
}
then use it:
container.GetOrAdd(s, _ => new HashSet<string>()).Add("value1");

Related

".Add" on Dictionary with a list as value

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

How to populate a dictionary of dictionaries of dictionaries?

I am trying to populate a dictionary of dictionaries of dictionaries. However when I try to populate my third dictionary I get the follow error below. How would I populate my second dictionary without getting an error?
The best overloaded method match for 'System.Collections.Generic.Dictionary<string,System.Collections.Generic.Dictionary<string,
System.Collections.Generic.List<string>>>.this[string]' has some invalid arguments
//code
ClientsData.Add(new MapModel.ClientInfo { Id = IDCounter, Doctors = new Dictionary<string, Dictionary<string,List<string>>>() });
ClientsData[0].Doctors.Add(Reader["DocID"].ToString(), new Dictionary<string,List<string>>());
ClientsData[0].Doctors[0].Add("Name", new List<string>(){ Reader["DocName"].ToString()});//Error occurs here
To access a dictionary like that you need to use a key, which in your case is a string:
ClientsData[0].Doctors[Reader["DocID"].ToString()].Add("Name", new List<string>(){ Reader["DocName"].ToString()});
If you want to use tripple dictonaries you can use the following snippet:
var dict = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
dict["level-one"] = new Dictionary<string, Dictionary<string, string>>();
dict["level-one"]["level-two"] = new Dictionary<string, string>();
dict["level-one"]["level-two"]["level-three"] = "hello";
Console.WriteLine(dict["level-one"]["level-two"]["level-three"]);
Or you can make your own wrapper like this:
public class TrippleDictionary<TKey, TValue>
{
Dictionary<TKey, Dictionary<TKey, Dictionary<TKey, TValue>>> dict = new Dictionary<TKey, Dictionary<TKey, Dictionary<TKey, TValue>>>();
public TValue this [TKey key1, TKey key2, TKey key3]
{
get
{
CheckKeys(key1, key2, key3);
return dict[key1][key2][key3];
}
set
{
CheckKeys(key1, key2, key3);
dict[key1][key2][key3] = value;
}
}
void CheckKeys(TKey key1, TKey key2, TKey key3)
{
if (!dict.ContainsKey(key1))
dict[key1] = new Dictionary<TKey, Dictionary<TKey, TValue>>();
if (!dict[key1].ContainsKey(key2))
dict[key1][key2] = new Dictionary<TKey, TValue>();
if (!dict[key1][key2].ContainsKey(key3))
dict[key1][key2][key3] = default(TValue);
}
}
And use it like this:
var tripple = new TrippleDictionary<string, string>();
tripple["1", "2", "3"] = "Hello!";
Console.WriteLine(tripple["1", "2", "3"]);
See Demo

Copy key values from NameValueCollection to Generic Dictionary

Trying to copy values from an existing NameValueCollection object to a Dictionary. I have the following code below to do that but seems the Add does not accept that my keys and values are as Strings
IDictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>();
public void copyFromNameValueCollection (NameValueCollection a)
{
foreach (var k in a.AllKeys)
{
dict.Add(k, a[k]);
}
}
Note: NameValueCollection contains String keys and values and so I simply want to provide here a method to allow copying of those to a generic dictionary.
Extension method plus linq:
public static Dictionary<string, string> ToDictionary(this NameValueCollection nvc) {
return nvc.AllKeys.ToDictionary(k => k, k => nvc[k]);
}
//example
var dictionary = nvc.ToDictionary();
It doesn't make sense to use generics here since you can't assign strings to some arbitrary generic type:
IDictionary<string, string> dict = new Dictionary<string, string>();
public void copyFrom(NameValueCollection a)
{
foreach (var k in a.AllKeys)
{
dict.Add(k, a[k]);
}
}
although you should probably create a method to create a new dictionary instead:
public static IDictionary<string, string> ToDictionary(this NameValueCollection col)
{
IDictionary<string, string> dict = new Dictionary<string, string>();
foreach (var k in col.AllKeys)
{
dict.Add(k, col[k]);
}
return dict;
}
which you can use like:
NameValueCollection nvc = //
var dictionary = nvc.ToDictionary();
If you want a general way of converting the strings in the collection into the required key/value types, you can use type converters:
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this NameValueCollection col)
{
var dict = new Dictionary<TKey, TValue>();
var keyConverter = TypeDescriptor.GetConverter(typeof(TKey));
var valueConverter = TypeDescriptor.GetConverter(typeof(TValue));
foreach(string name in col)
{
TKey key = (TKey)keyConverter.ConvertFromString(name);
TValue value = (TValue)valueConverter.ConvertFromString(col[name]);
dict.Add(key, value);
}
return dict;
}
parameters.AllKeys.ToDictionary(t => t, t => parameters[t]);
Use LINQ:
public static IDictionary<string, string> ToDictionary(this NameValueCollection collection)
{
return collection.Cast<string>().ToDictionary(k => k, v => collection[v]);
}
Usage:
IDictionary<string, string> dic = nv.ToDictionary();
Super-Short Version
var dataNvc = HttpUtility.ParseQueryString(data);
var dataCollection = dataNvc.AllKeys.ToDictionary(o => o, o => dataNvc[o]);
If you know that your dictionary is always going to contain strings, specify it to contain strings instead of making your class generic:
IDictionary<string, string> dict = new Dictionary<string, string>();
With this, things will "just work" as written (without the generic method specification).
If you need this to be a generic class, and hold generic data, you need some way to convert from string to TKey and string to TValue. You could provide delegates to your copy method to do this:
public void CopyFrom(NameValueCollection a, Func<string, TKey> keyConvert, Func<string, TValue> valueConvert)
{
foreach(var k in a.AllKeys)
{
dict.Add(keyConvert(k), valueConvert(a[k]));
}
}
You would then need to pass a delegate in that would perform the conversion from string to TValue and string to TKey.
You should not forget about EqualityComparer. But it is not a public property. So, you should use reflection to get it.
public static IEqualityComparer GetEqualityComparer(this NameObjectCollectionBase nameObjectCollection)
{
PropertyInfo propertyInfo = typeof(NameObjectCollectionBase).GetProperty("Comparer", BindingFlags.Instance | BindingFlags.NonPublic);
return (IEqualityComparer)propertyInfo.GetValue(nameObjectCollection);
}
public static IEqualityComparer<string> GetEqualityComparer(this NameValueCollection nameValueCollection)
{
return (IEqualityComparer<string>)((NameObjectCollectionBase)nameValueCollection).GetEqualityComparer();
}
public static Dictionary<string, string> ToDictionary(this NameValueCollection nameValueCollection)
{
Dictionary<string, string> dictionary =
nameValueCollection.AllKeys.ToDictionary(x => x, x => nameValueCollection[x], nameValueCollection.GetEqualityComparer());
return dictionary;
}

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

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

Categories

Resources