I've melihat beberapa cara yang berbeda untuk iterate atas sebuah kamus di C#. Apakah ada cara yang standar?
Jika anda mencoba untuk menggunakan Kamus generik di C# seperti anda akan menggunakan array asosiatif dalam bahasa lain:
foreach(var item in myDictionary)
{
foo(item.Key);
bar(item.Value);
}
Atau, jika anda hanya perlu untuk iterate atas koleksi kunci, menggunakan
foreach(var item in myDictionary.Keys)
{
foo(item);
}
Dan terakhir, jika anda're hanya tertarik pada nilai-nilai:
foreach(var item in myDictionary.Values)
{
foo(item);
}
(Perhatikan bahwa var
kata kunci opsional C# 3.0 dan fitur di atas, anda juga bisa menggunakan jenis yang tepat dari kunci/nilai-nilai berikut)
Dalam beberapa kasus, anda mungkin perlu sebuah counter yang dapat diberikan oleh bagi-loop implementasi. Untuk itu, LINQ menyediakan [ElementAt
][1] yang memungkinkan hal berikut:
for (int index = 0; index < dictionary.Count; index++) {
var item = dictionary.ElementAt(index);
var itemKey = item.Key;
var itemValue = item.Value;
}
[1]: https://msdn.microsoft.com/en-us/library/bb299233(v=vs. 110).aspx
Tergantung pada apakah anda'kembali setelah tombol atau nilai-nilai...
Dari MSDN Dictionary(TKey, TValue)
Kelas keterangan:
// When you use foreach to enumerate dictionary elements,
// the elements are retrieved as KeyValuePair objects.
Console.WriteLine();
foreach( KeyValuePair<string, string> kvp in openWith )
{
Console.WriteLine("Key = {0}, Value = {1}",
kvp.Key, kvp.Value);
}
// To get the values alone, use the Values property.
Dictionary<string, string>.ValueCollection valueColl =
openWith.Values;
// The elements of the ValueCollection are strongly typed
// with the type that was specified for dictionary values.
Console.WriteLine();
foreach( string s in valueColl )
{
Console.WriteLine("Value = {0}", s);
}
// To get the keys alone, use the Keys property.
Dictionary<string, string>.KeyCollection keyColl =
openWith.Keys;
// The elements of the KeyCollection are strongly typed
// with the type that was specified for dictionary keys.
Console.WriteLine();
foreach( string s in keyColl )
{
Console.WriteLine("Key = {0}", s);
}
Umumnya, meminta "terbaik" tanpa konteks tertentu seperti bertanya apa yang terbaik warna?
Di satu sisi, ada banyak warna dan ada's tidak ada warna terbaik. Hal ini tergantung pada kebutuhan dan sering di rasa, terlalu.
Di sisi lain, ada banyak cara untuk iterate atas Kamus dalam C# dan's tidak ada cara terbaik. Hal ini tergantung pada kebutuhan dan sering di rasa, terlalu.
foreach (var kvp in items)
{
// key is kvp.Key
doStuff(kvp.Value)
}
Jika anda hanya perlu nilai (memungkinkan untuk menyebutnya item
, lebih mudah dibaca dari kvp.Nilai
).
foreach (var item in items.Values)
{
doStuff(item)
}
Umumnya, pemula terkejut tentang urutan enumerasi dari Kamus.
LINQ menyediakan ringkas sintaks yang memungkinkan untuk menentukan urutan (dan banyak hal lain), misalnya:
foreach (var kvp in items.OrderBy(kvp => kvp.Key))
{
// key is kvp.Key
doStuff(kvp.Value)
}
Sekali lagi anda mungkin hanya perlu nilai. LINQ juga menyediakan solusi ringkas untuk:
item
, lebih mudah dibaca dari kvp.Nilai
)Di sini adalah:
foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value))
{
doStuff(item)
}
Ada lebih banyak digunakan di dunia nyata hal yang dapat anda lakukan dari contoh-contoh ini. Jika anda don't perlu urutan tertentu, hanya menempel "cara paling sederhana" (lihat di atas)!
Saya menghargai pertanyaan ini sudah memiliki banyak tanggapan tapi aku ingin melempar sebuah penelitian kecil.
Iterasi kamus dapat lebih lambat bila dibandingkan dengan iterasi sesuatu seperti array. Dalam tes saya iterasi lebih dari array mengambil 0.015003 detik sedangkan iterasi kamus (dengan jumlah yang sama dari unsur-unsur) mengambil 0.0365073 detik yang's 2.4 kali lebih lama! Meskipun saya telah melihat lebih banyak perbedaan. Sebagai perbandingan Daftar
Namun, itu adalah seperti membandingkan apel dan jeruk. Maksud saya adalah bahwa iterasi kamus lambat.
Kamus dioptimalkan untuk pencarian, sehingga dengan itu dalam pikiran saya've dibuat dengan dua metode. Satu hanya tidak foreach, yang lain iterates kunci lalu mendongak.
public static string Normal(Dictionary<string, string> dictionary)
{
string value;
int count = 0;
foreach (var kvp in dictionary)
{
value = kvp.Value;
count++;
}
return "Normal";
}
Yang satu ini banyak tombol dan iterates atas mereka, bukan (saya juga mencoba menarik tombol ke string[] namun perbedaan itu diabaikan.
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";
}
Dengan contoh ini normal foreach tes mengambil 0.0310062 dan tombol versi mengambil 0.2205441. Memuat semua tombol dan iterasi semua pencarian ini jelas lebih lambat!
Untuk tes akhir I've dilakukan iterasi sepuluh kali untuk melihat apakah ada manfaat untuk menggunakan tombol berikut (pada titik ini aku hanya penasaran):
Berikut ini's RunTest metode apakah yang membantu anda memvisualisasikan apa yang's terjadi.
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);
}
Di sini normal foreach berjalan mengambil 0.2820564 detik (sekitar sepuluh kali lebih lama dari satu iterasi mengambil - seperti yang kau'd harapkan). Iterasi di atas tombol mengambil 2.2249449 detik.
Diedit Untuk Menambahkan: Membaca beberapa jawaban lainnya membuat saya bertanya-tanya apa yang akan terjadi jika saya menggunakan Kamus<objek, objek> bukan Kamus<string, string>. Dalam contoh ini array mengambil 0.0120024 detik, daftar 0.0185037 detik dan kamus 0.0465093 detik. It's masuk akal untuk mengharapkan bahwa jenis data yang membuat perbedaan pada bagaimana jauh lebih lambat kamus.
Apa yang saya Kesimpulan?
Ada banyak pilihan. Favorit pribadi saya adalah dengan KeyValuePair
Dictionary<string, object> myDictionary = new Dictionary<string, object>();
// Populate your dictionary here
foreach (KeyValuePair<string,object> kvp in myDictionary)
{
// Do some interesting things
}
Anda juga dapat menggunakan Kunci dan nilai-Nilai Koleksi
C# 7.0 diperkenalkan Deconstructors dan jika anda menggunakan .NET Core 2.0+ Aplikasi, struct KeyValuePair<>
sudah termasuk Mendekonstruksi()
untuk anda. Jadi yang dapat anda lakukan:
var dic = new Dictionary<int, string>() { { 1, "One" }, { 2, "Two" }, { 3, "Three" } };
foreach (var (key, value) in dic) {
Console.WriteLine($"Item [{key}] = {value}");
}
//Or
foreach (var (_, value) in dic) {
Console.WriteLine($"Item [NO_ID] = {value}");
}
//Or
foreach ((int key, string value) in dic) {
Console.WriteLine($"Item [{key}] = {value}");
}
Dengan .NET Framework 4.7
satu dapat menggunakan dekomposisi
var fruits = new Dictionary<string, int>();
...
foreach (var (fruit, number) in fruits)
{
Console.WriteLine(fruit + ": " + number);
}
Untuk membuat kode ini bekerja di bawah C# versi, tambahkan Sistem.ValueTuple NuGet package
dan menulis di suatu tempat
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;
}
}
Anda disarankan di bawah ini untuk iterate
Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here
foreach (KeyValuePair<string,object> kvp in myDictionary) {
//Do some interesting things;
}
FYI, foreach
doesn't bekerja jika nilai dari tipe obyek.
Menggunakan C# 7, tambahkan ini metode penyuluhan untuk setiap proyek anda solusi:
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);
}
}
Dan menggunakan sintaks sederhana
foreach (var(id, value) in dict.Tuples())
{
// your code using 'id' and 'value'
}
Atau yang satu ini, jika anda lebih suka
foreach ((string id, object value) in dict.Tuples())
{
// your code using 'id' and 'value'
}
Di tempat tradisional
foreach (KeyValuePair<string, object> kvp in dict)
{
string id = kvp.Key;
object value = kvp.Value;
// your code using 'id' and 'value'
}
Ekstensi metode mengubah KeyValuePair
anda IDictionary<TKey, TValue>
menjadi sangat diketik tupel
, yang memungkinkan anda untuk menggunakan ini baru nyaman sintaks.
Itu mengkonversi -hanya - satu-yang diperlukan entri kamus untuk tupel
, sehingga TIDAK mengubah seluruh kamus untuk tupel
, jadi tidak ada masalah kinerja yang berkaitan dengan itu.
Ada yang hanya kecil biaya memanggil metode penyuluhan untuk menciptakan tupel
dibandingkan dengan menggunakan KeyValuePair
secara langsung, yang seharusnya TIDAK menjadi masalah jika anda menetapkan KeyValuePair
's properties Kunci
dan Nilai
untuk variabel loop baru pula.
Dalam prakteknya, ini baru sintaks sesuai sangat baik untuk sebagian besar kasus, kecuali untuk tingkat rendah ultra-tinggi kinerja skenario, di mana anda masih memiliki pilihan untuk hanya tidak menggunakannya pada tempat tertentu.
Check this out: Blog MSDN - fitur Baru pada C# 7
Kadang-kadang jika anda hanya membutuhkan nilai-nilai yang akan dihitung, gunakan kamus's kumpulan nilai:
foreach(var value in dictionary.Values)
{
// do something with entry.Value only
}
Dilaporkan oleh posting ini yang menyatakan itu adalah metode tercepat: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html
Saya menemukan metode ini dalam dokumentasi untuk DictionaryBase kelas di MSDN:
foreach (DictionaryEntry de di myDictionary)
{
//Melakukan beberapa hal dengan de.Nilai atau de.Kunci
}
Ini adalah satu-satunya yang saya bisa dapatkan berfungsi dengan benar di kelas yang diwarisi dari DictionaryBase.
Sebagai C# 7, anda dapat membongkar benda-benda ke dalam variabel. Saya percaya ini menjadi cara terbaik untuk iterate melalui kamus.
Contoh:
Membuat metode penyuluhan pada KeyValuePair<TKey, TVal>
yang mendekonstruksi ini:
public static void Deconstruct<TKey, TVal>(this KeyValuePair<TKey, TVal> pair, out TKey key, out TVal value)
{
key = pair.Key;
value = pair.Value;
}
Iterate atas setiap Kamus<TKey, TVal>
dengan cara berikut
// Dictionary can be of any types, just using 'int' and 'string' as examples.
Dictionary<int, string> dict = new Dictionary<int, string>();
// Deconstructor gets called here.
foreach (var (key, value) in dict)
{
Console.WriteLine($"{key} : {value}");
}
Saya tahu ini adalah pertanyaan kuno, tapi saya membuat beberapa ekstensi metode yang mungkin berguna:
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); }
}
Dengan cara ini saya bisa menulis kode seperti ini:
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););