Increasing a numeric value in a dictionary

I use the code below to increment or insert a value in a dictionary. If the key that I am incrementing does not exist, I would like to set its value to 1.

public void IncrementCount(Dictionary<int, int> someDictionary, int id) { int currentCount; if (someDictionary.TryGetValue(id, out currentCount)) { someDictionary[id] = currentCount + 1; } else { someDictionary[id] = 1; } } 

Is this a good way to do this?

+45
dictionary c #
Aug 20 '11 at 15:30
source share
6 answers

As it turned out, it makes sense to use ConcurrentDictionary, which has a convenient upsert: AddOrUpdate method.

So, I just used:

 someDictionary.AddOrUpdate(id, 1, (id, count) => count + 1); 
+53
Aug 20 '11 at 16:00
source share

Your code is ok. But here you can simplify a path that does not require branching in your code:

 int currentCount; // currentCount will be zero if the key id doesn't exist.. someDictionary.TryGetValue(id, out currentCount); someDictionary[id] = currentCount + 1; 

It depends on the fact that the TryGetValue method sets the value to the default value of its type if the key doesn't exist. In your case, the default value of int is 0 , which is exactly what you want.




UPD . Starting with C # 7.0, this snippet can be shortened with out variables :

 // declare variable right where it passed someDictionary.TryGetValue(id, out var currentCount); someDictionary[id] = currentCount + 1; 
+41
Aug 20 '11 at 16:10
source share

Here is a good extension method:

  public static void Increment<T>(this Dictionary<T, int> dictionary, T key) { int count; dictionary.TryGetValue(key, out count); dictionary[key] = count + 1; } 

Using:

 var dictionary = new Dictionary<string, int>(); dictionary.Increment("hello"); dictionary.Increment("hello"); dictionary.Increment("world"); Assert.AreEqual(2, dictionary["hello"]); Assert.AreEqual(1, dictionary["world"]); 
+12
Feb 20 2018-12-12T00:
source share

It is readable and the goal is clear. I think everything is in order. No need to invent smarter or shorter code; if it doesnโ€™t keep the intention as clear as your original version :-)

Saying this, a slightly shorter version:

 public void IncrementCount(Dictionary<int, int> someDictionary, int id) { if (!someDictionary.ContainsKey(id)) someDictionary[id] = 0; someDictionary[id]++; } 

If you have parallel access to the dictionary, do not forget to synchronize access with it.

+11
Aug 20 '11 at 15:37
source share

Just some measurements on .NET 4 for whole keys.

This is not quite the answer to your question, but for completeness, I measured the behavior of various classes useful for incrementing integers based on integer keys: simple Array , Dictionary (@Ani approach), Dictionary (simple approach), SortedDictionary (@Ani approach) and ConcurrentDictionary.TryAddOrUpdate .

Here are the results, adjusted to 2.5 ns for class packaging instead of direct use:

 Array 2.5 ns/inc Dictionary (@Ani) 27.5 ns/inc Dictionary (Simple) 37.4 ns/inc SortedDictionary 192.5 ns/inc ConcurrentDictionary 79.7 ns/inc 

And what a code .

Note that ConcurrentDictionary.TryAddOrUpdate is three times slower than Dictionary TryGetValue + indexer installer. And the latter is ten times slower than Array.

So, I would use an array if I knew that the key range is small, and the combined approach would otherwise.

+3
Jan 24 '17 at 12:50
source share

Here is a handy unit test for you to play with regarding ConcurrentDictionary and how to keep the values โ€‹โ€‹thread safe:

  ConcurrentDictionary<string, int> TestDict = new ConcurrentDictionary<string,int>(); [TestMethod] public void WorkingWithConcurrentDictionary() { //If Test doesn't exist in the dictionary it will be added with a value of 0 TestDict.AddOrUpdate("Test", 0, (OldKey, OldValue) => OldValue+1); //This will increment the test key value by 1 TestDict.AddOrUpdate("Test", 0, (OldKey, OldValue) => OldValue+1); Assert.IsTrue(TestDict["Test"] == 1); //This will increment it again TestDict.AddOrUpdate("Test", 0, (OldKey, OldValue) => OldValue+1); Assert.IsTrue(TestDict["Test"] == 2); //This is a handy way of getting a value from the dictionary in a thread safe manner //It would set the Test key to 0 if it didn't already exist in the dictionary Assert.IsTrue(TestDict.GetOrAdd("Test", 0) == 2); //This will decriment the Test Key by one TestDict.AddOrUpdate("Test", 0, (OldKey, OldValue) => OldValue-1); Assert.IsTrue(TestDict["Test"] == 1); } 
0
Jul 16 '15 at 19:12
source share



All Articles