在 C# 的 for 循环中修改字典
Modify a dictionary in a for loop in C#
我在 C/C++ 方面经验丰富,但在 C# 方面几乎是个新手。我的问题很简单。假设我们有一个包含整数键和值的散列 table,我们希望将散列 table 中的所有值递增 1。我们更愿意使用 O(1) 额外内存来完成此操作。
下面是一个解决方案,在我看来,它有点丑陋。有没有其他方法让它看起来更像样?
Dictionary<int, int> dict = new Dictionary<int, int>();
for (int i = 0; i < dict.Count; ++i)
{
dict[dict.Keys.ElementAt(i)]++;
}
PS:听说foreach
在C#中是只读的。但是,有没有像 C++ 中的 for(auto it& : dict) it.second++
这样的方法,我仍然可以使用它在 C# 中完成这个任务?
为什么不允许这样做?尝试分配给它可能不会做你想做的事——它不会修改原始集合的内容。这是因为变量 x 不是对列表中元素的引用 - 它是一个副本。
因为 KeyValuePair 具有键和值的只读属性,所以要在 foreach 中执行此操作,您需要第二个 Dictionnary 来添加这些项并处理原始项
Dictionary<int, int> dict = new Dictionary<int, int>();
dict.Add(0, 1);
dict.Add(1, 2);
dict.Add(2, 3);
Dictionary<int, int> dictOutput = new Dictionary<int, int>();
foreach (KeyValuePair<int,int> item in dict)
{
dictOutput.Add(item.Key, item.Value + 1);
}
dict.Dispose();
Dictionary<,>
本身并没有提供这样做的好方法 - 因为更新与键关联的值算作使任何迭代器无效的更改。 ConcurrentDictionary<,>
允许这样做,甚至有一个 AddOrUpdate
方法可以帮助您:
using System;
using System.Linq;
using System.Collections.Concurrent;
class Test
{
static void Main()
{
var dict = new ConcurrentDictionary<int, int>
{
[10] = 15,
[20] = 5,
[30] = 10
};
foreach (var key in dict.Keys)
{
dict.AddOrUpdate(key, 0, (k, v) => v + 1);
}
Console.WriteLine(string.Join("\r\n", dict.Select(kp => $"{kp.Key}={kp.Value}")));
}
}
您可以在这种情况下使用 foreach,但我们需要以不使用字典的方式来执行此操作,因为更新它会更改内部迭代器(这就是 foreach 跟上它所在位置的方式)迭代时,请查看此 SO 以获取更多详细信息:) 在此实现中,我们将迭代键列表,然后在迭代时更新每个键的值。
Dictionary<int, int> dict = new Dictionary<int, int>();
foreach (var i in dict.Keys.ToList())
{
dict[i]++;
}
Update 正如 Servy 指出的那样,我没有提到这个解决方案不是 O(1),而是 O(N)。
您的循环中不需要 dict.Keys.ElementAt(i)
索引。您可以将其视为一个数组。 Dictionary
s 是 C# 等同于 C++ 中的 Map
。您需要做的就是增加您的价值
for (int i = 0; i < dict.Count; i ++)
dict[i]++;
此外,如果您使用的是 Dictionary<int, int>
,则只需使用
int[] dict = new int[count];
反正你的键就是索引;但我真的只推荐使用 List<int>
。这样您就可以动态调整大小,而无需做所有额外的工作。
这样,您可以像这样创建 List<int>
:
List<int> lstDict = new List<int>;
int value; /*assign to whatever value you need to insert*/
int count; /*however many elements you need*/
for (int i = 0; i < count; i ++)
lstDict.Add(value);
//
// Whatever else you need to do
//
for (int i = 0; i < count; i ++)
lstDict[i]++;
有很多方法可以完成您想要完成的事情。您可以使用这些选项中的任何一个来实现相同的目的。如果您想坚持使用 Dictionary
s,只需使用我放在那里的第一个片段。我个人不会使用它们,除非我需要使用两种不同的数据类型,比如 Dictionary<string, int>
。
我在 C/C++ 方面经验丰富,但在 C# 方面几乎是个新手。我的问题很简单。假设我们有一个包含整数键和值的散列 table,我们希望将散列 table 中的所有值递增 1。我们更愿意使用 O(1) 额外内存来完成此操作。
下面是一个解决方案,在我看来,它有点丑陋。有没有其他方法让它看起来更像样?
Dictionary<int, int> dict = new Dictionary<int, int>();
for (int i = 0; i < dict.Count; ++i)
{
dict[dict.Keys.ElementAt(i)]++;
}
PS:听说foreach
在C#中是只读的。但是,有没有像 C++ 中的 for(auto it& : dict) it.second++
这样的方法,我仍然可以使用它在 C# 中完成这个任务?
为什么不允许这样做?尝试分配给它可能不会做你想做的事——它不会修改原始集合的内容。这是因为变量 x 不是对列表中元素的引用 - 它是一个副本。
因为 KeyValuePair 具有键和值的只读属性,所以要在 foreach 中执行此操作,您需要第二个 Dictionnary 来添加这些项并处理原始项
Dictionary<int, int> dict = new Dictionary<int, int>();
dict.Add(0, 1);
dict.Add(1, 2);
dict.Add(2, 3);
Dictionary<int, int> dictOutput = new Dictionary<int, int>();
foreach (KeyValuePair<int,int> item in dict)
{
dictOutput.Add(item.Key, item.Value + 1);
}
dict.Dispose();
Dictionary<,>
本身并没有提供这样做的好方法 - 因为更新与键关联的值算作使任何迭代器无效的更改。 ConcurrentDictionary<,>
允许这样做,甚至有一个 AddOrUpdate
方法可以帮助您:
using System;
using System.Linq;
using System.Collections.Concurrent;
class Test
{
static void Main()
{
var dict = new ConcurrentDictionary<int, int>
{
[10] = 15,
[20] = 5,
[30] = 10
};
foreach (var key in dict.Keys)
{
dict.AddOrUpdate(key, 0, (k, v) => v + 1);
}
Console.WriteLine(string.Join("\r\n", dict.Select(kp => $"{kp.Key}={kp.Value}")));
}
}
您可以在这种情况下使用 foreach,但我们需要以不使用字典的方式来执行此操作,因为更新它会更改内部迭代器(这就是 foreach 跟上它所在位置的方式)迭代时,请查看此 SO 以获取更多详细信息:) 在此实现中,我们将迭代键列表,然后在迭代时更新每个键的值。
Dictionary<int, int> dict = new Dictionary<int, int>();
foreach (var i in dict.Keys.ToList())
{
dict[i]++;
}
Update 正如 Servy 指出的那样,我没有提到这个解决方案不是 O(1),而是 O(N)。
您的循环中不需要 dict.Keys.ElementAt(i)
索引。您可以将其视为一个数组。 Dictionary
s 是 C# 等同于 C++ 中的 Map
。您需要做的就是增加您的价值
for (int i = 0; i < dict.Count; i ++)
dict[i]++;
此外,如果您使用的是 Dictionary<int, int>
,则只需使用
int[] dict = new int[count];
反正你的键就是索引;但我真的只推荐使用 List<int>
。这样您就可以动态调整大小,而无需做所有额外的工作。
这样,您可以像这样创建 List<int>
:
List<int> lstDict = new List<int>;
int value; /*assign to whatever value you need to insert*/
int count; /*however many elements you need*/
for (int i = 0; i < count; i ++)
lstDict.Add(value);
//
// Whatever else you need to do
//
for (int i = 0; i < count; i ++)
lstDict[i]++;
有很多方法可以完成您想要完成的事情。您可以使用这些选项中的任何一个来实现相同的目的。如果您想坚持使用 Dictionary
s,只需使用我放在那里的第一个片段。我个人不会使用它们,除非我需要使用两种不同的数据类型,比如 Dictionary<string, int>
。