Initializing a dictionary to custom default values - c#

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.

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.

.Net Dictionary with forced unique values

Is it possible to force a Dictionary to have unique values? See the following example.
Dictionary<string, string> types = new Dictionary<string, string>()
{
{"1", "one"},
{"2", "two"},
{"3", "three"}
};
In the event some one tried to execute the following line, they should receive an error.
types.Add("4","one");
I know this is not how a dictionary is built to operate and the correct answer may be to use a different/custom data structure.
Keep two data structures; your regular dictionary and a HashSet<string> for the values. When you would like to add an item first check if the value is in the hash set. If it's not, then you know it's safe to add to both the dictionary and the set. (Also ensure you remove items from both collections on removal.)
If this is done in enough places then it may be worth creating your own IDictionary<K,V> implementation that uses both a regular Dictionary and a HashSet internally, so that you don't need to do so much work when using it. If this particular structure is only used in just a few places, it may not be worth the investment to create such a class.
You probably want to implement IDictionary and internally just call the corresponding Dictionary<TKey,TValue> methods. Also, you want a HashSet<TValue>. And then, on your Add method you would first check to see if your hashset.Contains(value). If it does, then you throw an exception.
On the other hand, do you really NEED this behavior? What if you just use a HashSet<Tuple<string,string>>. Then, any duplicates are just ignored. Or do you really NEED the data structure to throw an exception? If you don't, that's what I would go with.
Edit: good point #Alexei Levenkov. If you will have the same value with different keys, then the HashSet approach doesn't give you what you originally asked for. That would only be applicable if you were expecting the SAME key/value pairs.
Check for types.ContainsValue before adding
string str = "one";
if (!types.ContainsValue(str)) //doesn't add if its already there
{
types.Add("4", str);
}
unfortunately Dictionary provided by framework doesn't provide this feature.
Fastest workaround would be build something like this
public class UniqueValueDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
public new void Add(TKey key, TValue value)
{
if (this.ContainsValue(value))
{
throw new ArgumentException("value already exist");
}
base.Add(key, value);
}
public new TValue this[TKey key]
{
get
{
return base[key];
}
set
{
if (this.ContainsValue(value))
{
throw new ArgumentException("value already exist");
}
base[key] = value;
}
}
}
Or something like the following(which is better in performance but not memory)
public class UniqueValueDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
Dictionary<TValue, TKey> valueAsKey = new Dictionary<TValue, TKey>();
public new void Add(TKey key, TValue value)
{
if (valueAsKey.ContainsKey(value))
{
throw new ArgumentException("value already exist");
}
base.Add(key, value);
valueAsKey.Add(value, key);
}
public new TValue this[TKey key]
{
get
{
return base[key];
}
set
{
if (valueAsKey.ContainsKey(value))
{
throw new ArgumentException("value already exist");
}
if (!this.ContainsKey(key))
{
this.Add(key, value);
}
else
{
base[key] = value;
valueAsKey[value] = key;
}
}
}
//You may need to handle remove as well
}
Note:this will work only when you use UniqueValueDictionary<TKey, TValue> type, If you cast to Dictionary<TKey, TValue> you can add duplicate values.
As pointed in comments you can build something like this inheriting from IDictionary<TKey, TValue> not Dictionary<TKey, TValue> taking this as an idea.

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

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

C# Indexer Property Question

I have a class like this:
public class SomeClass
{
private const string sessionKey = "__Privileges";
public Dictionary<int, Privilege> Privileges
{
get
{
if (Session[sessionKey] == null)
{
Session[sessionKey] = new Dictionary<int, Privilege>();
}
return (Dictionary<int, Privilege>)Session[sessionKey];
}
}
}
Now, if Ido this...
var someClass = new SomeClass();
var p = someClass.Privileges[13];
... and there is no key 13, I will get an error like this:
The given key was not present in the dictionary.
I would like to have a property that can be accessed in the same way as above, but will return a default object in case of the absence of the key.
I tried creating an indexer property like this...
public Privilege Privileges[int key]
{
get
{
try { return _privileges[key]; }
catch { return new Privilege(); }
}
}
... but it looks like that's not a C# 2008 language feature.
How can I access the property in the same way, but get the default object if the key isn't present?
C# does not supported named indexers, as you have discovered.
Have you considered using a regular method instead of an indexer property? Not every programming problem requires the use fancy syntax to solve. Yes, you could create your own IDictionary implementation with an aggregated dictionary and change the property access behavior - but is that really necessary for something that just fetches a value or returns a default?
I would add a method like this to your class:
protected Privilege GetPrivilege(int key)
{
try { return _privileges[key]; }
catch { return new Privilege(); }
}
or better yet, avoid exception handling as a flow control mechanism:
protected Privilege GetPrivilge( int key )
{
Privilege priv;
if( _privileges.TryGetValue( key, out priv ) )
return priv;
else
return new Privilege();
}
You'll have to define your own IDictionary-based class with an indexer that has the desired behavior, and return an instance of that, rather than the stock Dictionary class, in your property getter.
Indexers in C# can only be used with the this keyword.
I suspect you want something like this:
public Privilege this[int key]
{
get
{
try { return _privileges[key]; }
catch { return default(Privelege); }
}
}
which you can define either directly in SomeClass so that you can access a privelege item like:
SomeClass foo;
var bar = foo[100];
or define this indexer in a custom class that implements from IDictionary<TKey, TValue> (and contains a Dictionary<TKey, TValue internally for actually storing the data). You could then use it like:
SomeClass foo;
var bar = foo.Priveleges[100];
Which is the syntax you seem to propose, and which may be most appropiate, though it takes a bit more effort.
You should use this syntax to retrieve the value:
public Privilege this[int key]
{
get
{
var value = (Privilege)null;
if(!_privileges.TryGetValue(key, out value))
value = new Privilege();
return value;
}
}
I have a need for this kind of use of IDictionary a lot, so I made some extension methods:
public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key)
{
TValue v = default(TValue);
d.TryGetValue(key, out v);
return v;
}
public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key, Func<TValue> value)
{
TValue v = d.Get(key);
if (v == null)
{
v = value();
d.Add(key, v);
}
return v;
}
Now you could write:
public Privilege this[int key]
{
get
{
return _privileges.Get(key, () => new Privilege());
}
}

Categories

Resources