Find-or-insert with only one lookup in C# Dictionary - c#

I'm a former C++/STL programmer trying to code a fast marching algorithm using C#/.NET technology...
I'm searching for an equivalent of STL method map::insert that insert a value at given key if not exists, else returns an iterator to the existing key-value pair.
The only way I found does this with two lookups: one inside TryGetValue and another one in Add method:
List<Point> list;
if (!_dictionary.TryGetValue (pcost, out list))
{
list = new List<Point>();
dictionary.Add (pcost, list);
}
list.Add(new Point { X = n.x, Y = n.y });
Is there something that explains why this is not possible using .NET containers? Or did I missed some point?

You can just assign your value in the following way:
var dict = new Dictionary<int, int>();
dict[2] = 11;
if value with key 2 does not exist - it will be added and otherwise it will be just overriden.
Dictionary does not have method GetOrAdd, but ConcurrentDictionary from C# 4.0 does:
var dict = new ConcurrentDictionary<int, int>();
dict[2] = 10;
int a = dict.GetOrAdd(2, 11);// a == 10

The standard generic dictionary does not support this, the 2 lookups are required. Though the cost of the look ups are normally negligible so this isn't a problem, and you can often get better results tuning other parts of the system rather than trying to micro-optimise dictionary lookups.
The only dictionary that comes with .net that supports this that I know of is ConcurrentDictionary with the method GetOrAdd. Though now you're paying the cost of synchronization instead.

Is there something that explains why
this is not possible using .NET
containers ?
Without knowing the real background, I assume it is because of simplicity of the Dictionary. There are only the basic, easy to understand functions: Add, Remove a.s.o., while the index operator does a little bit of magic, which was probably assumed to be intuitive.

Sadly, there isn't one in bcl's implementation. The closest alternative is doing two lookups, but one can have a generic extension method to make it easy, as shown here
public static T GetOrAdd<S, T>(this IDictionary<S, T> dict, S key,
Func<T> valueCreator)
{
T value;
return dict.TryGetValue(key, out value) ? value : dict[key] = valueCreator();
}
But there is C5's implementation which does this out of the box. The method definition looks like this:
public virtual bool FindOrAdd(K key, ref V value)
{
}
I don't know why they don't accept a Func<V> instead of V to defer object creation. C5 has a lot of nice similar tricks, for eg,
public virtual bool Remove(K key, out V value)
public virtual bool Update(K key, V value, out V oldvalue)
public virtual bool UpdateOrAdd(K key, V value, out V oldvalue)

Starting from .NET 6, it is now possible to implement a GetOrAdd extension method for the Dictionary<TKey, TValue> class that takes a key and a valueFactory, and hashes the key only once. The new API is the CollectionsMarshal.GetValueRefOrAddDefault method, with this signature:
// Gets a reference to a TValue in the specified dictionary, adding a new entry
// with a default value if the key does not exist.
public static ref TValue? GetValueRefOrAddDefault<TKey,TValue> (
Dictionary<TKey,TValue> dictionary, TKey key, out bool exists);
This is a ref returning method. It can be used to implement the GetOrAdd like this:
/// <summary>
/// Adds a key/value pair to the dictionary by using the specified function
/// if the key does not already exist. Returns the new value, or the
/// existing value if the key exists.
/// </summary>
public static TValue GetOrAdd<TKey, TValue>(
this Dictionary<TKey, TValue> dictionary,
TKey key,
Func<TKey, TValue> valueFactory)
{
ArgumentNullException.ThrowIfNull(dictionary);
ArgumentNullException.ThrowIfNull(valueFactory);
ref TValue value = ref CollectionsMarshal
.GetValueRefOrAddDefault(dictionary, key, out bool exists);
if (!exists)
{
try { value = valueFactory(key); }
catch { dictionary.Remove(key); throw; }
}
return value;
}
Usage example:
List<Point> list = dictionary.GetOrAdd(pcost, key => new List<Point>());
list.Add(new Point { X = n.x, Y = n.y });
Online demo, featuring also an overload with generic parameter TArg.
The try/catch in the implementation is required in order to remove the empty entry, in case the valueFactory throws an exception. Otherwise the exception would leave the dictionary in a corrupted state (containing a key with a default value).
Btw a proposal to add this method in the standard .NET libraries has been submitted on GitHub, but it didn't generate enough traction and it was closed.

Old question, but I may have just stumbled across an acceptable solution. I use a combination of TryGetValue, ternary operator and index assignment.
var thing = _dictionary.TryGetValue(key, out var existing) ? existing : _dictionary[key] = new Thing();
I have written a small example for that.
class Program
{
private static readonly Dictionary<string, string> _translations
= new Dictionary<string, string>() { { "en", "Hello world!" } };
private static string AddOrGetTranslation(string locale, string defaultText)
=> _translations.TryGetValue(locale, out var existingTranslation)
? existingTranslation
: _translations[locale] = defaultText;
static void Main()
{
var defaultText = "#hello world#";
Console.WriteLine(AddOrGetTranslation("en", defaultText)); // -> Hello world!
Console.WriteLine(AddOrGetTranslation("de", defaultText)); // -> #hello world#
Console.WriteLine(AddOrGetTranslation("de", "differentDefaultText")); // -> #hello world#
_translations["de"] = "Hallo Welt!";
Console.WriteLine(AddOrGetTranslation("de", defaultText)); // -> Hallo Welt!
}
}
EDIT: ⚠️ There is an uncertainty of this solution. See comments on the solution.

You can create extension method for that:
IDictionary<string, Point> _dictionary = GetDictionary();
_dictionary.GetOrAdd( "asdf" ).Add( new Point(14, 15) );
// ... elsewhere ...
public static class DictionaryExtensions {
public static List<TValue> GetOrAdd<TKey, TValue>( this IDictionary<TKey, List<TValue>> self, TKey key ) {
List<TValue> result;
self.TryGetValue( key, out result );
if ( null == result ) {
// the key value can be set to the null
result = new List<TValue>();
self[key] = result;
}
return result;
}
}

Related

How to read the value from a Dictionary via .TryGetValue() if the value is a tuple?

I have a dictionary of type
Dictionary<int, (float, float)>
when trying to read the value from it I can't use this way
if (myDict.TryGetValue(1, out (float tupleItem1, float tupleItem2))) { /* ... */ }
because then I get compile errors
The way it works is
if (myDict.TryGetValue(1, out (float, float) theTuple)) { /* ... */ }
Is there a way I can directly initialize the variables like so?
if (!myDict.TryGetValue(1, out (float tupleItem1, float tupleItem2)))
{
/* handle if not found */
tupleItem1 = 111;
tupleItem2 = -12345;
}
You can't deconstruct directly in an out parameter yet unfortunately, see this proposal.
You'll have to deconstruct it yourself:
if (!myDict.TryGetValue(1, out var result))
{
result = (111, -12345);
}
You can improve this situation slightly with an extension method:
public static class DictionaryExtensions
{
public static TValue? TryGetValue<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key) where TValue : struct
{
return dict.TryGetValue(key, out var result) ? result : null;
}
}
This lets you write:
if (myDict.TryGetValue(1) is not (float tupleItem1, float tupleItem2))
{
tupleItem1 = 111;
tupleItem2 = -12345;
}
If you find yourself doing this a lot, you could write a simple little extension method to make it more readable:
public static class DictionaryExt
{
public static TValue TryGetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, Func<TValue> getDefault)
{
return dict.TryGetValue(key, out var value)
? value
: getDefault();
}
}
Then your sample code could looks something like this:
var dict = new Dictionary<int, (float, float)>();
var result = dict.TryGetValueOrDefault(1, () => (111, -12345));
Console.WriteLine(result);
I chose to use Func<TValue> rather than TValue for the default so that you don't have to create a default value that isn't going to be used in the case that the dictionary already contains the key.
If you want a slightly simpler syntax and you don't care that the default is created for every call regardless of whether it's actually needed you could write it like this instead:
public static class DictionaryExt
{
public static TValue TryGetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue defaultValue)
{
return dict.TryGetValue(key, out var value)
? value
: defaultValue;
}
}
Which would be called like this:
var dict = new Dictionary<int, (float, float)>();
var result = dict.TryGetValueOrDefault(1, (111, -12345));
Console.WriteLine(result);
You could of course include both methods in DictionaryExt for more flexibility.
(It's also entirely possible that the overhead of creating a Func<TValue> for every call is greater than creating a tuple for each call, so if you're worried about performance you should test it. In either case, you could pass in a precreated Func or Tuple to avoid the creation overhead.)

How can I write this in one line without duplicate dictionary name and key?

how can I write this in c# (latest version) in one line without dublicate dictionary name and key:
someDict[key] = someDict[key].MakeSomeChanges(1);
I found something like that:
_ = someDict[key].MakeSomeChanges(1);
but unfortunately that not assign changed value.
public static int[] MakeSomeChanges(this int[] array, int a)
{
//some logic
return x.ToArray();
}
Any ideas?
Not sure if following helps and it's also not one line, but it could be a way to avoid the repetition and is reusable for any modification or dictionary type.
Since you already use an extension method, add another one:
public static void Modify<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue intialValue, Func<TValue, TValue> modify)
{
bool exists = dict.TryGetValue(key, out TValue existingValue);
TValue value = exists ? existingValue : intialValue;
dict[key] = modify(value);
}
With this on board you could use:
someDict.Modify(key, new int[0], arr => arr.MakeSomeChanges(1));
Where MakeSomeChanges could be a method call(like above) or an inline logic.

Initializing a dictionary to custom default values

I am trying to create a for loop that invokes a function of several instance of class A in a dictionary, and if there is no value for a key, it creates it and then invokes it.
It seems to me as if there must be a way to create a value upon first access to a key.
I am currently using this code though I think it is not the best possible practice:
(dictionary[i] = dictionary.ContainsKey(arr[i]) ? dictionary[i] : new A()).Push(10);
Is there a cleaner for such a problem in C#?
ConcurrentDictionary has a GetOrAdd method (and other useful methods like AddOrUpdate, TryRemove etc.). If just a plain dictionary had GetOrAdd you could use that...
Luckily, you can create an extension method in a static class which you probably should name DictionaryExtensions:
public static TValue GetOrAdd<TKey, TValue>(
this IDictionary<TKey, TValue> dictionary,
TKey key,
Func<TKey, TValue> valueFactory)
{
if (dictionary == null)
throw new ArgumentNullException(nameof(dictionary));
if (key == null)
throw new ArgumentNullException(nameof(key));
if (valueFactory == null)
throw new ArgumentNullException(nameof(valueFactory));
if (dictionary.TryGetValue(key, out var existingValue))
return existingValue;
var value = valueFactory(key);
dictionary.Add(key, value);
return value;
}
How to use it:
dictionary.GetOrAdd(i, () => new A()).Push(10);
This version uses a value factory so that new A() is only executed in case it is required. Another ConcurrentDictionary.GetOrAdd() overload uses a value provided as parameter which you might consider as an alternative.
I find that creating extension methods like this that closely mirrors the methods on ConcurrentDictionary is very useful.
I'd say a cleaner code would look something like this:
var key = arr[i];
var hasKey = dictionary.ContainsKey(key);
if (!hasKey)
dictionary.Add(key, new A());
var itemToUse = dictionary[key];
itemToUse.Push(10);
Although it seems to me you are looking for something shorter. I guess what you are really asking is a short-hand method that does:
Returns the value for a given key if the key exists, else adds the key to the dictionary with some default value.
I think the above code tells a lot more about the intent, but in case you want something different, I can think of following two solutions.
The first one is an extension method for getting the item:
public static TValue Get<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
{
var hasKey = dictionary.ContainsKey(key);
if (!hasKey)
dictionary.Add(key, defaultValue);
return dictionary[key];
}
You would use it as:
dict.Get(arr[i], defaultValue: new A())
.Push(10);
The second solution I can think of is a new derivative of Dictionary:
class DefaultDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
private readonly Func<TKey, TValue> _defaultValueFactory;
public DefaultDictionary(TValue defaultValue)
{
_defaultValueFactory = new Func<TKey, TValue>(x => defaultValue);
}
public DefaultDictionary(Func<TValue> defaultValueFactory)
{
_defaultValueFactory = new Func<TKey, TValue>(x => defaultValueFactory()) ?? throw new ArgumentNullException(nameof(defaultValueFactory));
}
public DefaultDictionary(Func<TKey, TValue> defaultValueFactory)
{
_defaultValueFactory = defaultValueFactory ?? throw new ArgumentNullException(nameof(defaultValueFactory));
}
public new TValue this[TKey key]
{
get
{
var hasKey = ContainsKey(key);
if (!hasKey)
{
var defaultValue = _defaultValueFactory(key);
Add(key, defaultValue);
}
return base[key];
}
set
{
base[key] = value;
}
}
}
The usage of this goes like:
var dictionary = new DefaultDictionary<string, A>(() => new A());
// ...
dictionary[arr[i]].Push(10);
I must warn you about something, this derivative of Dictionary hides the index operator. And since using IDictionary as types for members is a common practice (e.g. private IDictionary<string, A> dictionary as a member), you can't use the overloaded version without casting. So either cast your variable to DefaultDictionary every time you want to use the overloaded indexer, or have an interface for this new dictionary like:
interface IDefaultDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
new TValue this[TKey key] { get; set; }
}
And have your members, variables use it as their defining type:
private IDefaultDictionary<string, A> dictionary;
But this also means as a concrete class you must now use DefaultDictionary, and that's the trade-off.

looking for an appropriate data structure(preferably Dictionary and List) for this scenario

In a method call an object is getting passed it.
From this object I can get two things: an ItemData propery and a Row property so for example:
oPTL.ItemData, oPTL.Row
I want to have a data structure that each time this method is called it can update this data structure so for example one time oPTL.ItemData is "Spread1" and oPTL.Row is 2 so we should be able to save that Spread1 has value 2...next call for example we should be able to save "Spread3" has value 3..next call "Spread1" has ALSO value 4 , etc...
So it is like a Dictionary<String,<List>> but still I have problem with declaring and using it this way in the code, any code sample you can help me with?
You can use a dictionary where the values are Lists:
IDictionary<string, List<int>> rows = new Dictionary<string, List<int>>();
To populate it you can use this extension method:
public static class DictionaryDefaultExtension
{
public static TValue GetOrDefault<TKey, TValue>(
this IDictionary<TKey, TValue> dictionary,
TKey key,
Func<TValue> defaultValue)
{
TValue result;
if (dictionary.TryGetValue(key, out result))
{
return result;
}
else
{
TValue value = defaultValue();
dictionary[key] = value;
return value;
}
}
}
Use like this:
d.GetOrDefault(oPTL.ItemData, () => new List<int>()).Add(oPTL.Row);
What you're looking for is Dictionary<string, List<int>> - assuming your .ItemData and .Row properties are in fact string and int respectively.
When you read item with "Spread1" value, you first check whether such key already exists in dictionary by calling .ContainsKey(string) method. If so, you add new Row value - if not, you create new key with brand new list, like in example below:
var myItems = new Dictionary<string, List<int>>();
// ...
if (myItems.ContainsKey(newItem.ItemData))
{
// myItems[newItem.ItemData] actually contains List<int> we created at some
// point in the other part of if-else.
// The .Add method we call here belongs to List
List<int> itemValues = myItems[newItem.ItemData];
itemValues.Add(newItem.Row);
}
else
{
myItems.Add(newItem.ItemData, new List<int> { newItem.Row });
}
Edited to add clarification with two .Add methods.

Is there a Dictionary<string, object> collection which allows multiple keys?

I currently have a menu with subitems that is being stored in this dictionary variable:
private Dictionary<string, UserControl> _leftSubMenuItems
= new Dictionary<string, UserControl>();
So I add views to the e.g. the "Customer" section like this:
_leftSubMenuItems.Add("customers", container.Resolve<EditCustomer>());
_leftSubMenuItems.Add("customers", container.Resolve<CustomerReports>());
But since I am using a Dictionary, I can only have one key named "customers".
My natural tendency would be to now create a custom struct with properties "Section" and "View", but is there a .NET collection is better suited for this task, something like a "MultiKeyDictionary"?
ANSWER:
Thanks maciejkow, I expanded your suggestion to get exactly what I needed:
using System;
using System.Collections.Generic;
namespace TestMultiValueDictionary
{
class Program
{
static void Main(string[] args)
{
MultiValueDictionary<string, object> leftSubMenuItems = new MultiValueDictionary<string, object>();
leftSubMenuItems.Add("customers", "customers-view1");
leftSubMenuItems.Add("customers", "customers-view2");
leftSubMenuItems.Add("customers", "customers-view3");
leftSubMenuItems.Add("employees", "employees-view1");
leftSubMenuItems.Add("employees", "employees-view2");
foreach (var leftSubMenuItem in leftSubMenuItems.GetValues("customers"))
{
Console.WriteLine(leftSubMenuItem);
}
Console.WriteLine("---");
foreach (var leftSubMenuItem in leftSubMenuItems.GetAllValues())
{
Console.WriteLine(leftSubMenuItem);
}
Console.ReadLine();
}
}
public class MultiValueDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>>
{
public void Add(TKey key, TValue value)
{
if (!ContainsKey(key))
Add(key, new List<TValue>());
this[key].Add(value);
}
public List<TValue> GetValues(TKey key)
{
return this[key];
}
public List<TValue> GetAllValues()
{
List<TValue> list = new List<TValue>();
foreach (TKey key in this.Keys)
{
List<TValue> values = this.GetValues(key);
list.AddRange(values);
}
return list;
}
}
}
Answer 2:
Thanks Blixt for the tip about yield, here is GetAllValues with that change:
public IEnumerable<TValue> GetAllValues()
{
foreach (TKey key in this.Keys)
{
List<TValue> values = this.GetValuesForKey(key);
foreach (var value in values)
{
yield return value;
}
}
}
Answer 2 refactored further:
Here is a much more succinct way to do the same thing, thanks Keith:
public IEnumerable<TValue> GetAllValues()
{
foreach (var keyValPair in this)
foreach (var val in keyValPair.Value)
yield return val;
}
If you need variable number of values for one key, why not create Dictionary<string, List<UserControl>> ? Furthermore, you could inherit this class and create your own Add, get same syntax you're using now. This way you can avoid manual adding of empty lists before adding new control.
sth like this:
class MultiValueDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>>
{
public void Add(TKey key, TValue value)
{
if(!ContainsKey(key))
Add(key, new List<TValue>());
this[key].Add(value);
}
}
Check out NGenerics' HashList. It's a Dictionary which maintains a list of values for each key. Wintellect's PowerCollections library also has a handy MultiDictionary class which does things like automatically clean up when you remove the last value associated with a given key.
How about making the container value type a list:
private Dictionary<string, List<UserControl>> _leftSubMenuItems =
new Dictionary<string, List<UserControl>>();
if (!_leftSubMenuItems.ContainsKey("customers"))
{
_leftSubMenuItems["customers"] = new List<UserControl>();
}
_leftSubMenuItems["customers"].Add(container.Resolve<EditCustomer>());
_leftSubMenuItems["customers"].Add(container.Resolve<CustomerReports>());
Just a few tweaks...
public class MultiValueDictionary<TKey, TValue> :
Dictionary<TKey, List<TValue>>
{
public void Add(TKey key, TValue value)
{
List<TValue> valList;
//a single TryGetValue is quicker than Contains then []
if (this.TryGetValue(key, out valList))
valList.Add(value);
else
this.Add( key, new List<TValue> { value } );
}
//this can be simplified using yield
public IEnumerable<TValue> GetAllValues()
{
//dictionaries are already IEnumerable, you don't need the extra lookup
foreach (var keyValPair in this)
foreach(var val in keyValPair.Value);
yield return val;
}
}
The .NET framework 3.5 includes a special LINQ Lookup class.
It is similar to a dictionary except that it can handle multiple items with the same key. When you do a search using a given key, instead of receiving a single element, you receive a group of elements that match that key.
I read that it is a hashtable under the covers so it is fast for retrieving.
You use it something like this:
var example1 = (from element in ListWithDuplicates
select element)
.ToLookup(A => A.Name);
There are a bunch of caveats:
The Lookup class has no public constructor, so you cant just create a Lookup object, it seems to only be available using the .ToLookup syntax.
You cannot edit it once it has been created, no Add or Remove etc.
Apparently its not serializable
Using the grouped data can be a bit tricky
Theres a great article here discussing the Lookup and its implications in more detail.
No, there's no better built-in collection. I think your "natural tendency" is perfectly suited for solving this problem, as those are not really "same keys," but unique keys composed of different parts and Dictionary does the job. You can also nest dictionary (makes sense if you have large number of values for each name):
Dictionary<string, Dictionary<Type, object>> dict = ...;
var value = (T)dict[name][typeof(T)];
This approach will resolve to the element using a single hash table lookup. If you maintain a list of items for each element, you'll have to linearly traverse the list each time you need an element to lookup which defeats the purpose of using a Dictionary in the first place.
I don't know of a "MultiKeyDictionary". I'd recommend using a struct and overriding GetHashCode, Equals and implementing IEquatable<StructName> (which is used by Dictionary<TKey,TValue>).
Are you looking to store multiple entries per key together? Somethign like this ?

Categories

Resources