-1

I'm trying to increment a value that's the value of a dictionary inside another dictionary and I just can't get it to work.

Dictionary<string, Dictionary<string, int>> logs = new Dictionary<string, Dictionary<string, int>>();
...
...
logs[username].Then(x => x.Value++) // If I use .Select(), the x represents a key value pair.

Unsurprisingly it doesn't work because .Then() doesn't exist in C# so how can I achieve what I'm trying to do?

EDIT: I tried doing

using System.Threading.Tasks;

Dictionary<string, Dictionary<string, int>> logs = new Dictionary<string, Dictionary<string, int>>();
...
...
logs[username].ContinueWith(x => x.Value++)

But it gives me the error that Dictionary<string, int> does not contain a definition for ContinueWith.

Detry
  • 9
  • 4
  • 5
    logs[username][yourKey]++ ? – Martheen Apr 04 '21 at 08:04
  • What exactly are you trying to do? Run through the dictionary and increments each of the values by 1? – Marko Apr 04 '21 at 08:07
  • I'm logging a username as the key of the first dictionary. Then I'm logging the ip address as the key of the second dictionary (the one within the first one) I'm logging the amount of times the ip address has been seen in the value of the second dictionary. Then if the username and the ip address have been seen before, I add 1 to the value of the second dictionary. – Detry Apr 04 '21 at 08:09
  • 1
    `then()` is applied on a `Promise`, but your `logs` is a dictionary? What would be the equivalient of you code in JS. `someojbect = {...}; someobject.then()` This doesn't make any sense either. – derpirscher Apr 04 '21 at 08:10
  • I mean @Martheen gave you the answer on how to set/increment the value on the nested dictionary. – Marko Apr 04 '21 at 08:16
  • Why do you need `Then`? Where is Task or Async operation? – Enver Arslan Apr 04 '21 at 08:17
  • Since I have the pair of {ip, } I need to increment the value of the second dictionary somehow. logs[username] returns a Dictionary so I don't know why I can't just call it's value and increment it. – Detry Apr 04 '21 at 08:26
  • 1
    @Martheen already supplied the answer ```logs[username]``` returns the value from the first dictionary, which is you second dictionary, now you want the data linked to the ip, so ```logs[username][ip]```. incrementing it is just this: ```logs[username][ip]++``` – Kevin Verstraete Apr 04 '21 at 08:37
  • You want to increment _what_? It's a dictionary, so it can have multiple pairs of keys and values. _Which_ pair's value do you want to increment? – Sweeper Apr 04 '21 at 08:38

1 Answers1

2

What you're doing looks like incrementing the values in the inner dictionary for a given key.

Here is one way to do it:

//using System.Linq

var logs = new Dictionary<string, Dictionary<string, int>>();

logs["user1"] = new Dictionary<string, int>{ {"x", 1}, {"y",2} };

// To increment values of all entries for a user
var userLogs = logs["user1"];
foreach( var userKeys in userLogs.Keys.ToList()) // Please don't miss the ToList()
{
    userLogs[userKeys] += 1;
}

If you wish of a one liner and/or lambdas we could try the following:

logs["user1"].Keys.ToList().ForEach(k => logs["user1"][k] += 1);

If you are trying to increment one value something like the following works:

logs["user1"]["key1"] += 1;
tymtam
  • 24,269
  • 5
  • 71
  • 101
  • 2
    The ToList shouldn't be needed as you aren't mutating the Dictionary's Keys or the Key collection itself – pinkfloydx33 Apr 04 '21 at 08:38
  • @pinkfloydx33 Sure? Something like [this (C# source encoded in URL)](https://tio.run/##TY4xC8IwFIT3/oqjU6W1uFddFBxEEBzFISZRgzWBvFgpJb89ptVCeTz4OI674zTnxsoQ3qT0HaeWnHyVG1PXkjtlNJU7qaVVvErIMac4eM2IcESXAH@pMUrgwJTOZoMMNMxCYAUtP9iqIYnZdknOxpYCSrs1ungpSwss4IuerxPmExYTliP7aii6xfGMP5D1jc8YDFHuZUvjEECcY9glz39@n/TvkxC@) will throw a run-time exception with _Collection was modified; enumeration operation may not execute._ So I guess a `.ToList` is required. Same if I do `+= 1` instead of `++`. Either is going to use the `set` accessor of the indexer, `d["c"] = tmp`, and it counts as modification. – Jeppe Stig Nielsen Apr 04 '21 at 09:10
  • No because you aren't modifying the collection in that manner... You're modifying the value portion of an object already stored by Key. If you were adding/removing keys then yes you would need it. At least it doesn't throw an error on SharpLab or when I try it locally with netcore3/5 – pinkfloydx33 Apr 04 '21 at 09:16
  • [Here is the code from the answer](https://tio.run/##dVA9a8MwEN39Kx5e6lA3wV3TZGmhQ1MItFvIIJRLIpAlqlPSGuPf7p7yYQi0g@D09L50mh@0D9T3BzZuh4@GI9XjZ28t6Wi84/ErOQpGT7MbxsK4r2mWcVTRaGirmLHM2gy4QEdvNnhXxhUjAdMDcFQB1u8YMzj6xos5RajQPHEMYl7@BRkX5/NiJGHJIslX@YEpVPn6f58katHmP3mJqitlamR67NBdfCYTfHqh6UA1uSjV7IEYfgtlLQQJRq5bH6CQ0ob@6bI4/@Gmy/TEEAEpvS8G6hs1LDGDbJyAUYpfWlJM2Hh3F1Eb2V/ck5RaGI6nnV23hkG8ujqucT9DdY7ssnS6vv8F). It blows up with the version of the runtime used by `tio.run`. Are you saying there is a version of .NET where it is different? What version do you have? – Jeppe Stig Nielsen Apr 04 '21 at 09:29
  • I get different results in 3.1 (needs ToList()) and 5 (doesn't need ToList()). – tymtam Apr 04 '21 at 09:36
  • Yes, there seems to have been changed something in the runtime at some point. On [SharpLab](https://sharplab.io/), with the exact same code as in my previous comment, when I select "Results: Run" in the top of the right frame, it depends on the Platforms selected in the top middle. We end up using the `set` accessor of the indexer of `Dictionary`. Something like `userLogs[userKeys] = tmp;` Depending on the situation, this setter can either _add_ a key/value pair to the dictionary, or _update_ the value part of an existing pair. So they must have liberalized their policy in the latter case. – Jeppe Stig Nielsen Apr 04 '21 at 09:44
  • https://stackoverflow.com/questions/66939923/what-changed-in-net-5-that-makes-it-not-throw-when-changing-dictionary-values-i :) – tymtam Apr 04 '21 at 09:51
  • 1
    The lesson learned after reading @tymtam's new thread, is that if you target .NET 5 (from November 2020) or later, you do not need `.ToList()` in this situation, but if you target an older version of .NET Core, or .NET Framework, you _do_ need it. – Jeppe Stig Nielsen Apr 04 '21 at 11:53