我看到了一些不同的方法来迭代C#中的字典。有标准的方法吗?
当前回答
一般来说,在没有特定上下文的情况下要求“最佳方式”就像要求什么是最好的颜色?
一方面,有很多颜色,没有最好的颜色。这取决于需求,也常常取决于口味。
另一方面,有很多方法可以在C#中迭代字典,没有最好的方法。这取决于需求,也常常取决于口味。
最直接的方式
foreach (var kvp in items)
{
// key is kvp.Key
doStuff(kvp.Value)
}
如果您只需要值(允许将其称为item,比kvp.value更可读)。
foreach (var item in items.Values)
{
doStuff(item)
}
如果您需要特定的排序顺序
一般来说,初学者对词典的列举顺序感到惊讶。
LINQ提供了一种简洁的语法,允许指定顺序(以及许多其他事情),例如:
foreach (var kvp in items.OrderBy(kvp => kvp.Key))
{
// key is kvp.Key
doStuff(kvp.Value)
}
同样,您可能只需要值。LINQ还提供了一个简洁的解决方案:
直接迭代值(允许将其称为item,比kvp.value更可读)但按按键排序
这里是:
foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value))
{
doStuff(item)
}
从这些示例中可以看到更多真实世界的用例。如果您不需要特定的订单,只需坚持“最直接的方式”(见上文)!
其他回答
我想说foreach是标准的方法,尽管这显然取决于你想要什么
foreach(var kvp in my_dictionary) {
...
}
这就是你要找的吗?
如果您希望在默认情况下迭代值集合,我相信您可以实现IEnumerable<>,其中T是字典中值对象的类型,“this”是字典。
public new IEnumerator<T> GetEnumerator()
{
return this.Values.GetEnumerator();
}
您也可以在用于多线程处理的大型字典上尝试此操作。
dictionary
.AsParallel()
.ForAll(pair =>
{
// Process pair.Key and pair.Value here
});
在.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;
}
}
我很感激这个问题已经得到了很多回应,但我想做一点研究。
与在数组等对象上迭代相比,在字典上迭代可能会相当慢。在我的测试中,对数组的迭代耗时0.015003秒,而对字典(元素数量相同)的迭代耗时0.0365073秒,是其2.4倍!尽管我看到了更大的差异。相比之下,List介于0.00215043秒之间。
然而,这就像比较苹果和橙子。我的观点是迭代字典很慢。
字典是为查找而优化的,因此考虑到这一点,我创建了两种方法。一个简单地执行foreach,另一个迭代键然后查找。
public static string Normal(Dictionary<string, string> dictionary)
{
string value;
int count = 0;
foreach (var kvp in dictionary)
{
value = kvp.Value;
count++;
}
return "Normal";
}
这一个加载键并对其进行迭代(我也尝试将键拉入字符串[],但差异可以忽略不计。
public static string Keys(Dictionary<string, string> dictionary)
{
string value;
int count = 0;
foreach (var key in dictionary.Keys)
{
value = dictionary[key];
count++;
}
return "Keys";
}
在本例中,正常的foreach测试花费0.0310062,密钥版本花费0.2205441。加载所有键并迭代所有查找显然要慢很多!
在最后一次测试中,我已经执行了十次迭代,看看使用这里的键是否有任何好处(此时我只是好奇):
这是RunTest方法,如果它可以帮助您可视化正在发生的事情。
private static string RunTest<T>(T dictionary, Func<T, string> function)
{
DateTime start = DateTime.Now;
string name = null;
for (int i = 0; i < 10; i++)
{
name = function(dictionary);
}
DateTime end = DateTime.Now;
var duration = end.Subtract(start);
return string.Format("{0} took {1} seconds", name, duration.TotalSeconds);
}
这里,正常的foreach运行耗时0.2820564秒(大约是单个迭代耗时的十倍——正如您所预期的那样)。按键的迭代耗时2.2249449秒。
编辑添加:阅读其他一些答案让我怀疑如果我使用字典而不是字典会发生什么。在本例中,数组耗时0.0120024秒,列表耗时0.0185037秒,字典耗时0.0465093秒。可以合理地预期,数据类型会对字典的速度产生影响。
我的结论是什么?
如果可以的话,请避免在字典上进行迭代,因为它们比在具有相同数据的数组上进行迭代要慢得多。如果您确实选择遍历字典,不要太聪明,尽管速度较慢,但可能会比使用标准foreach方法做得更糟。
推荐文章
- 实体框架核心:在上一个操作完成之前,在此上下文中开始的第二个操作
- 如何为构造函数定制Visual Studio的私有字段生成快捷方式?
- 如何使用JSON确保字符串是有效的JSON。网
- AppSettings从.config文件中获取值
- 通过HttpClient向REST API发布一个空体
- 如何合并字典的字典?
- 如何检查IEnumerable是否为空或空?
- 自动化invokerrequired代码模式
- 在c#代码中设置WPF文本框的背景颜色
- 在c#中,什么是单子?
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Swift:声明一个空字典
- 将JSON字符串转换为HashMap
- 我如何循环通过一组记录在SQL Server?