-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
  • 5
  • 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
  • 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
  • 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
  • 31,798
  • 8
  • 86
  • 126
  • 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