trygetvalue - c# keyvaluepair
迭代字典的最佳方法是什么? (17)
我已经看到了几种不同的方法来迭代C#中的字典。 有标准的方法吗?
Dictionary <TKey,TValue>它是c#中的泛型集合类,它以键值格式存储数据.Key必须是唯一的,它不能为null,而值可以是重复的和null。因为字典中的每个项目都是被视为KeyValuePair <TKey,TValue>表示密钥及其值的结构。 因此我们应该在元素的迭代过程中采用元素类型KeyValuePair <TKey,TValue>。 以下是示例。
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1,"One");
dict.Add(2,"Two");
dict.Add(3,"Three");
foreach (KeyValuePair<int, string> item in dict)
{
Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}
一般来说,在没有特定背景的情况下询问“最好的方式”就像问什么是最好的颜色。
一方面,有很多颜色,没有最好的颜色。 这取决于需要,也经常取决于口味。
另一方面,有许多方法可以在C#中迭代一个Dictionary而且没有最好的方法。 这取决于需要,也经常取决于口味。
最直截了当的方式
foreach (var kvp in items)
{
// key is kvp.Key
doStuff(kvp.Value)
}
如果只需要值(允许调用它,比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)
}
您可以从这些示例中获得更多真实用例。 如果您不需要特定订单,只需坚持“最直接的方式”(见上文)!
使用.NET Framework 4.7
可以使用分解
var fruits = new Dictionary<string, int>();
...
foreach (var (fruit, number) in fruits)
{
Console.WriteLine(fruit + ": " + number);
}
要使此代码适用于较低的C#版本,请添加System.ValueTuple NuGet package
并在某处写入
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;
}
}
使用C#7 ,将此扩展方法添加到解决方案的任何项目中:
public static class IDictionaryExtensions
{
public static IEnumerable<(TKey, TValue)> Tuples<TKey, TValue>(
this IDictionary<TKey, TValue> dict)
{
foreach (KeyValuePair<TKey, TValue> kvp in dict)
yield return (kvp.Key, kvp.Value);
}
}
并使用这个简单的语法
foreach (var(id, value) in dict.Tuples())
{
// your code using 'id' and 'value'
}
或者这个,如果你愿意的话
foreach ((string id, object value) in dict.Tuples())
{
// your code using 'id' and 'value'
}
代替传统
foreach (KeyValuePair<string, object> kvp in dict)
{
string id = kvp.Key;
object value = kvp.Value;
// your code using 'id' and 'value'
}
扩展方法将IDictionary<TKey, TValue>
的KeyValuePair
转换为强类型tuple
,允许您使用这种新的舒适语法。
它将-just-所需的字典条目转换为tuples
,因此它不会将整个字典转换为tuples
,因此没有与此相关的性能问题。
与直接使用KeyValuePair
相比,调用创建tuple
的扩展方法只有一个小成本,如果你将KeyValuePair
的属性Key
和Value
分配给新的循环变量,这应该不是问题。
在实践中,这种新语法非常适合大多数情况,除了低级超高性能场景,您仍然可以选择不在特定位置使用它。
看看这个: MSDN博客 - C#7中的新功能
只是想加上我的2美分,因为大多数答案与foreach-loop有关。 请看下面的代码:
Dictionary<String, Double> myProductPrices = new Dictionary<String, Double>();
//Add some entries to the dictionary
myProductPrices.ToList().ForEach(kvP =>
{
kvP.Value *= 1.15;
Console.Writeline(String.Format("Product '{0}' has a new price: {1} $", kvp.Key, kvP.Value));
});
Altought这又增加了一个'.ToList()'调用,可能会有一点性能提升(正如foreach vs someList.Foreach(){}所指出的那样),特别是当使用大型字典并且并行运行时没有选项/根本没有效果。
另外,请注意,您无法为foreach循环中的“Value”属性赋值。 另一方面,您也可以操纵'Key',可能会让您在运行时遇到麻烦。
当您只想“读取”键和值时,您也可以使用IEnumerable.Select()。
var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );
在某些情况下,您可能需要一个可以通过for循环实现提供的计数器。 为此,LINQ提供了ElementAt
,它支持以下功能:
for (int index = 0; index < dictionary.Count; index++) {
var item = dictionary.ElementAt(index);
var itemKey = item.Key;
var itemValue = item.Value;
}
如果说,你想默认迭代值集合,我相信你可以实现IEnumerable <>,其中T是字典中值对象的类型,“this”是一个Dictionary。
public new IEnumerator<T> GetEnumerator()
{
return this.Values.GetEnumerator();
}
字典是特殊列表,而列表中的每个值都有一个键,它也是一个变量。 字典的一个很好的例子是电话簿。
Dictionary<string, long> phonebook = new Dictionary<string, long>();
phonebook.Add("Alex", 4154346543);
phonebook["Jessica"] = 4159484588;
请注意,在定义字典时,我们需要提供两种类型的泛型定义 - 键的类型和值的类型。 在这种情况下,键是一个字符串,而值是一个整数。
还有两种方法可以使用括号运算符或使用Add方法向字典添加单个值。
要检查字典中是否有某个键,我们可以使用ContainsKey方法:
Dictionary<string, long> phonebook = new Dictionary<string, long>();
phonebook.Add("Alex", 415434543);
phonebook["Jessica"] = 415984588;
if (phonebook.ContainsKey("Alex"))
{
Console.WriteLine("Alex's number is " + phonebook["Alex"]);
}
要从字典中删除项目,我们可以使用Remove方法。 通过键从字典中删除项目非常快速且非常高效。 使用其值从List中删除项目时,该过程缓慢且效率低,与字典“删除”功能不同。
Dictionary<string, long> phonebook = new Dictionary<string, long>();
phonebook.Add("Alex", 415434543);
phonebook["Jessica"] = 415984588;
phonebook.Remove("Jessica");
Console.WriteLine(phonebook.Count);
您建议在下面进行迭代
Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here
foreach (KeyValuePair<string,object> kvp in myDictionary) {
//Do some interesting things;
}
仅供参考,如果值为object类型,则foreach
不起作用。
我会说foreach是标准的方式,虽然它显然取决于你在寻找什么
foreach(var kvp in my_dictionary) {
...
}
这就是你要找的东西吗?
我在MSDN上的DictionaryBase类的文档中找到了这个方法:
foreach (DictionaryEntry de in myDictionary)
{
//Do some stuff with de.Value or de.Key
}
这是我能够在从DictionaryBase继承的类中正确运行的唯一一个。
我将利用.NET 4.0+并提供最初接受的答案的更新答案:
foreach(var entry in MyDic)
{
// do something with entry.Value or entry.Key
}
有很多选择。 我最喜欢的是KeyValuePair
Dictionary<string, object> myDictionary = new Dictionary<string, object>();
// Populate your dictionary here
foreach (KeyValuePair<string,object> kvp in myDictionary)
{
// Do some interesting things
}
您还可以使用键和值集合
有时,如果您只需要枚举值,请使用字典的值集合:
foreach(var value in dictionary.Values)
{
// do something with entry.Value only
}
该帖子报道称这是最快的方法: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html : http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html
迭代字典的最简单形式:
foreach(var item in myDictionary)
{
Console.WriteLine(item.Key);
Console.WriteLine(item.Value);
}
除了排名最高的帖子之外,还有使用过程之间的讨论
foreach(KeyValuePair<string, string> entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
要么
foreach(var entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
最完整的是以下因为你可以从初始化看到字典类型,kvp是KeyValuePair
var myDictionary = new Dictionary<string, string>(x);//fill dictionary with x
foreach(var kvp in myDictionary)//iterate over dictionary
{
// do something with kvp.Value or kvp.Key
}
var dictionary = new Dictionary<string, int>
{
{ "Key", 12 }
};
var aggregateObjectCollection = dictionary.Select(
entry => new AggregateObject(entry.Key, entry.Value));