我看到了一些不同的方法来迭代C#中的字典。有标准的方法吗?
当前回答
在某些情况下,您可能需要由for循环实现提供的计数器。为此,LINQ提供了启用以下功能的ElementAt:
for (int index = 0; index < dictionary.Count; index++) {
var item = dictionary.ElementAt(index);
var itemKey = item.Key;
var itemValue = item.Value;
}
其他回答
最好的答案当然是:想一想,如果你计划迭代,你是否可以使用比字典更合适的数据结构-正如Vikas Gupta在问题讨论开始时已经提到的那样。但作为整个主题的讨论仍然缺乏令人惊讶的好选择。一个是:
SortedList<string, string> x = new SortedList<string, string>();
x.Add("key1", "value1");
x.Add("key2", "value2");
x["key3"] = "value3";
foreach( KeyValuePair<string, string> kvPair in x )
Console.WriteLine($"{kvPair.Key}, {kvPair.Value}");
为什么它会被认为是在字典上迭代的代码味道(例如,通过foreach(KeyValuePair<,>)?
清洁编码的基本原则:“表达意图!”罗伯特·C·马丁在《干净的代码》中写道:“选择能揭示意图的名字”。很明显,单是命名太弱了。“表达(揭示)每一个编码决策的意图”更好地表达了这一点。
一个相关的原则是“最小惊讶原则”。
为什么这与遍历字典有关?选择字典表达了选择数据结构的意图,该数据结构主要用于按关键字查找数据。如今,.NET中有太多的替代方案,如果您想遍历键/值对,可以选择其他选项。
此外:如果您迭代某个项目,您必须揭示项目的排序方式和预期排序方式!尽管Dictionary的已知实现按照添加项的顺序对密钥集合进行排序-AFAIK,Dictionary没有关于订购的可靠规范(有吗?)。
但替代方案是什么?
TLDR:SortedList:如果您的集合没有变得太大,一个简单的解决方案是使用SortedList<,>,它还为键/值对提供了完整的索引。
微软有一篇关于提及和解释试衣系列的长文:键控集合
提到最重要的:KeyedCollection<,>和SortedDictionary<,>。SortedDictionary<,>比SortedList快一点,仅当它变大时才插入,但缺少索引,并且仅当插入的O(log n)优先于其他操作时才需要。如果您真的需要O(1)来插入并接受较慢的迭代,则必须使用简单的Dictionary<,>。显然,对于每种可能的操作,没有最快的数据结构。。
此外,还有ImmutableSortedDictionary<,>。
如果一个数据结构不是您所需要的,那么从Dictionary<,>或甚至从新的ConcurrentDictionary>派生,并添加显式迭代/排序函数!
我知道这是一个非常古老的问题,但我创建了一些可能有用的扩展方法:
public static void ForEach<T, U>(this Dictionary<T, U> d, Action<KeyValuePair<T, U>> a)
{
foreach (KeyValuePair<T, U> p in d) { a(p); }
}
public static void ForEach<T, U>(this Dictionary<T, U>.KeyCollection k, Action<T> a)
{
foreach (T t in k) { a(t); }
}
public static void ForEach<T, U>(this Dictionary<T, U>.ValueCollection v, Action<U> a)
{
foreach (U u in v) { a(u); }
}
这样我可以编写如下代码:
myDictionary.ForEach(pair => Console.Write($"key: {pair.Key}, value: {pair.Value}"));
myDictionary.Keys.ForEach(key => Console.Write(key););
myDictionary.Values.ForEach(value => Console.Write(value););
如果要使用for循环,可以执行以下操作:
var keyList=new List<string>(dictionary.Keys);
for (int i = 0; i < keyList.Count; i++)
{
var key= keyList[i];
var value = dictionary[key];
}
在.NET Framework 4.7中,可以使用分解
var fruits = new Dictionary<string, int>();
...
foreach (var (fruit, number) in fruits)
{
Console.WriteLine(fruit + ": " + number);
}
要使此代码在较低的C#版本上运行,请添加System.ValueTuple NuGet包并在某处编写
public static class MyExtensions
{
public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple,
out T1 key, out T2 value)
{
key = tuple.Key;
value = tuple.Value;
}
}
foreach(KeyValuePair<string, string> entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
推荐文章
- 在Bash中模拟do-while循环
- 防止在ASP中缓存。NET MVC中使用属性的特定操作
- 转换为值类型'Int32'失败,因为物化值为空
- c#中有任何连接字符串解析器吗?
- 加快R中的循环操作
- 在Linq中转换int到字符串到实体的问题
- 是否可以动态编译和执行c#代码片段?
- 创建自定义MSBuild任务时,如何从c#代码获取当前项目目录?
- 在STL地图中,使用map::insert比[]更好吗?
- c#和Java的主要区别是什么?
- 在c#中创建一个特定时区的DateTime
- .NET中的属性是什么?
- csproj文件中的“Service Include”是干什么用的?
- 如何使用try catch进行异常处理是最佳实践
- 替换字符串中第一次出现的模式