640

How to update value for a specific key in a dictionary Dictionary<string, int>?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Amit
  • 25,106
  • 25
  • 75
  • 116
  • I have a complex type stored as value in dictionary. When I want to change a property of an stored value, I get CS1612. Therefore I must take a way around: var v = dict[c]; v.dprop = c.sprop; dict[c] = v; – peter70 Nov 16 '18 at 15:03
  • @peter70, only with the structs, it is because structs are returned by value, so "updating" them would update only temporary, local copy of it. – greenoldman Nov 28 '20 at 06:24

10 Answers10

1026

Just point to the dictionary at given key and assign a new value:

myDictionary[myKey] = myNewValue;
IT ppl
  • 2,626
  • 1
  • 39
  • 56
ccalboni
  • 12,120
  • 5
  • 30
  • 38
  • So this simple method seems also to be a better substitute for the well known ".Add" and ".TryGetValue" method without the necessity to change the value. (?) At least, if it doesn't matter to overwrite keys, for example in a situation where it is not excluded that keys are written more than once in a loop. Or does somebody see any disadvantages? Especially because .Add has the ptifall for beginners that if the if-wrapper or TryGetValue is forgotten, it can work fine in tests and with other test data where the .Add is called twice for the same key it will throw an exception. – Philm Jan 14 '17 at 09:52
  • 8
    the interesting point of this operation is that, it UPSERT (key, value) into dictionary. brilliant! – Søren Jan 16 '17 at 07:51
  • 1
    As Pini stated, this should be the answer to the question. due the right thing and change it. – Leo Gurdian Mar 17 '17 at 18:53
  • 2
    @Philm, one huge disadvantage is, this approach is treated as modifying entire dictionary, in other words it is **not** just an update. – greenoldman Sep 27 '20 at 07:50
  • @greenoldman Are you sure? Why is this modifying the "entire dictionary"? Do you have a reference to what you're talking about? Surely this is an operator on the dictionary, and calling a method does exactly the same thing... – nevelis Nov 27 '20 at 19:00
  • 2
    @nevelis, var dict = new Dictionary() { { "a" , 0 }, { "b", 0 }, }; foreach (var key in dict.Keys) dict[key] = 1; } } If it was merely an update of the **value** you wouldn't get exception when iterating over **keys**, because superficially one has nothing to do with the other. – greenoldman Nov 28 '20 at 06:19
  • 2
    @greenoldman ahh I see what you mean, I misunderstood what you meant by “modifying the whole dictionary” you are referring to it invalidating any current iterator right? – nevelis Nov 30 '20 at 05:33
  • @nevelis, yes, because unfortunately dictionary sees it is as modified collection, despite the fact, keys were not modified here (on the surface). – greenoldman Dec 01 '20 at 05:58
  • When iterating and doing this how do you handle `Collection was modified; enumeration operation may not execute`? – mxmissile Jan 22 '21 at 18:21
214

It's possible by accessing the key as index

for example:

Dictionary<string, int> dictionary = new Dictionary<string, int>();
dictionary["test"] = 1;
dictionary["test"] += 1;
Console.WriteLine (dictionary["test"]); // will print 2
Amit
  • 25,106
  • 25
  • 75
  • 116
  • 16
    If there is no item "test" in the List, then list["test"] = list["test"] + 1; will raise KeyNotFoundException! The pure assignment of a non existing indexer will work. list["test"] = 1; – Steven Spyrka May 26 '15 at 09:38
  • 1
    Can you also use list["test"]++;? – aufty Jan 08 '16 at 18:02
  • 1
    @aufty you can write `++dictionary["test"];` or `dictionary["test"]++;` but only if there is an entry in the dictionary with the key value "test" — example: `if(dictionary.ContainsKey("test")) ++dictionary["test"];` `else dictionary["test"] = 1; // create entry with key "test"` – gerryLowry May 20 '18 at 00:29
62

You can follow this approach:

void addOrUpdate(Dictionary<int, int> dic, int key, int newValue)
{
    int val;
    if (dic.TryGetValue(key, out val))
    {
        // yay, value exists!
        dic[key] = val + newValue;
    }
    else
    {
        // darn, lets add the value
        dic.Add(key, newValue);
    }
}

The edge you get here is that you check and get the value of corresponding key in just 1 access to the dictionary. If you use ContainsKey to check the existance and update the value using dic[key] = val + newValue; then you are accessing the dictionary twice.

max_force
  • 769
  • 6
  • 12
  • 4
    Instead of `dic.Add(key, newValue);` you can use use `dic[key] = newvalue;`. – Macke Apr 13 '15 at 04:15
  • 1
    What happens if you do "dic[key] = value" and "key" doesn't exist? – superpuccio Aug 03 '15 at 11:41
  • 2
    @superpuccio you get a KeyNotFoundException – ntroncos Sep 21 '15 at 23:52
  • 15
    @ntroncos not true, it will add that key to the dictionary with the value provided. += will not work on a non-existing key though, since it is just syntactic sugar for dic[key] = value + dic[key]. – lastas Dec 18 '15 at 14:26
  • 2
    This should be the answer to the question as it regards updating the dictionary not just adding to it. – The Lonely Coder Dec 16 '16 at 09:41
  • @max_force this the best answer to the asked question. He asked about how to update not about to set the value. This is why the best answer – Selman May 11 '18 at 09:46
  • This post was the key to my solution, and I would agree that it is overall the best. I was not in the situation of a for or foreach loop, I was needing to find a value in a large list and update each time I found it - only by using the TryGetValue to set a value and then update it - this was what I was needing to do. Perfect for me - and rare area that I have not had to do. – Mark W. Mitchell Jul 03 '20 at 15:08
  • more shorten: `int val = 0; dic.TryGetValue(key, out val); dic[key] = val + newValue;` – oolionoo Dec 23 '21 at 10:38
  • There is no suggestion that the OP wants to add the passed value to any existing value for the key; the desire is more likely to be to overwrite it. Therefore you'd simply want: `dic[key] = newValue;` ...and this could be the entirety of the method. – Kaitain Feb 26 '23 at 14:26
18

Use LINQ: Access to dictionary for the key and change the value

Dictionary<string, int> dict = new Dictionary<string, int>();
dict = dict.ToDictionary(kvp => kvp.Key, kvp => kvp.Value + 1);
Community
  • 1
  • 1
INT_24h
  • 1,491
  • 1
  • 10
  • 6
17

This simple check will do an upsert i.e update or create.

if(!dictionary.TryAdd(key, val))
{
    dictionary[key] = val;
}
saad bin sami
  • 364
  • 4
  • 11
  • why not simply do dictionary[key] = value; which will simply update the value directly. – Deb Aug 05 '21 at 14:11
  • Because if you simply do: dictionary[key] = value; then you will be overwriting the value each time. Considering the fact that your dictionaries can be static and shared across different threads, and overwriting may require a lock, i would prefer to first check whether the key/value exists or not? if not, then only then we should update it. @Deb – saad bin sami Jul 25 '22 at 14:17
11

Here is a way to update by an index much like foo[x] = 9 where x is a key and 9 is the value

var views = new Dictionary<string, bool>();

foreach (var g in grantMasks)
{
    string m = g.ToString();
    for (int i = 0; i <= m.Length; i++)
    {
        views[views.ElementAt(i).Key] = m[i].Equals('1') ? true : false;
    }
}
Dean Seo
  • 5,486
  • 3
  • 30
  • 49
Matthew
  • 411
  • 4
  • 14
3
  1. update - modify existent only. To avoid side effect of indexer use:

    int val;
    if (dic.TryGetValue(key, out val))
    {
        // key exist
        dic[key] = val;
    }
    
  2. update or (add new if value doesn't exist in dic)

    dic[key] = val;
    

    for instance:

    d["Two"] = 2; // adds to dictionary because "two" not already present
    d["Two"] = 22; // updates dictionary because "two" is now present
    
Vlad
  • 1,977
  • 19
  • 44
1

This may work for you:

Scenario 1: primitive types

string keyToMatchInDict = "x";
int newValToAdd = 1;
Dictionary<string,int> dictToUpdate = new Dictionary<string,int>{"x",1};

if(!dictToUpdate.ContainsKey(keyToMatchInDict))
   dictToUpdate.Add(keyToMatchInDict ,newValToAdd );
else
   dictToUpdate[keyToMatchInDict] = newValToAdd; //or you can do operations such as ...dictToUpdate[keyToMatchInDict] += newValToAdd;

Scenario 2: The approach I used for a List as Value

int keyToMatch = 1;
AnyObject objInValueListToAdd = new AnyObject("something for the Ctor")
Dictionary<int,List<AnyObject> dictToUpdate = new Dictionary<int,List<AnyObject>(); //imagine this dict got initialized before with valid Keys and Values...

if(!dictToUpdate.ContainsKey(keyToMatch))
   dictToUpdate.Add(keyToMatch,new List<AnyObject>{objInValueListToAdd});
else
   dictToUpdate[keyToMatch] = objInValueListToAdd;

Hope it's useful for someone in need of help.

Mozart
  • 2,117
  • 2
  • 20
  • 38
1

You Can Also Use This Method :

Dictionary<int,int> myDic = new();
if (myDic.ContainsKey(1))
{
    myDic[1] = 1234; // or use += to update it 
}

Or By Value :

if (myDic.ContainsValue(1))
{
    //do something ... 
}
AliSalehi
  • 159
  • 1
  • 1
  • 13
0

This extension method allows a match predicate delegate as the dictionary key selector, and a separate delegate to perform the dictionary value replacement, so it's completely open as to the type of key/value pair being used:

public static void UpdateAll<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, Func<TKey, TValue, bool> matchPredicate, Func<TValue, TValue> updatePredicate)
{
  var keys = dictionary.Keys.Where(k => matchPredicate(k, dictionary[k])).ToList();
  foreach (var key in keys)
  {
    dictionary[key] = updatePredicate(dictionary[key]);
  }
}

Example usage:

    Dictionary<int, string> dict = new Dictionary<int, string>();
    dict.Add(1, "One");
    dict.Add(2, "Two");
    dict.Add(3, "Three");

    //Before
    foreach(var kvp in dict){
      Console.WriteLine(kvp.Value);
    }

    dict.UpdateAll(
        matchPredicate: (k, v) => k >= 2, //Update any dictionary value where the key is >= 2
        updatePredicate: (v) => v = v + " is greater than One"
      );

    //After
    foreach(var kvp in dict){
      Console.WriteLine(kvp.Value);
    }
BobT
  • 66
  • 1
  • 1
  • 5