Saya telah melihat beberapa cara berbeda untuk beralih ke kamus di C #. Apakah ada cara standar?
c#
dictionary
loops
Jake Stewart
sumber
sumber
Jawaban:
sumber
var entry
lebih baik dalam hal itu, dan dengan demikian saya memilih jawaban ini pada tampilan kedua daripada yang di atas.var
ketika Anda tidak tahu jenisnya adalah praktik yang buruk.var
hanya berfungsi jika jenisnya diketahui pada waktu kompilasi. Jika Visual Studio mengetahui jenisnya maka tersedia bagi Anda untuk mengetahuinya juga.Jika Anda mencoba menggunakan Kamus generik dalam C # seperti Anda akan menggunakan array asosiatif dalam bahasa lain:
Atau, jika Anda hanya perlu mengulangi pengumpulan kunci, gunakan
Dan terakhir, jika Anda hanya tertarik pada nilai-nilai:
(Perhatikan bahwa
var
kata kunci adalah fitur C # 3.0 opsional dan di atas, Anda juga dapat menggunakan jenis kunci / nilai yang tepat di sini)sumber
myDictionary
(kecuali itu adalah nama sebenarnya tentu saja). Saya pikir menggunakan var baik ketika jenisnya jelas misalnyavar x = "some string"
tetapi ketika tidak segera jelas saya pikir itu kode malas yang menyakitkan pembaca kode / resensivar
harus digunakan hemat, menurut pendapat saya. Khususnya di sini, itu tidak konstruktif: jenisnyaKeyValuePair
mungkin relevan dengan pertanyaan.var
memiliki tujuan yang unik dan saya tidak percaya itu adalah gula 'sintaksis'. Menggunakannya dengan sengaja adalah pendekatan yang tepat.Dalam beberapa kasus, Anda mungkin memerlukan penghitung yang mungkin disediakan oleh implementasi for-loop. Untuk itu, LINQ menyediakan
ElementAt
yang memungkinkan berikut ini:sumber
ElementAt
operasi O (n)?.ElementAt
dalam konteks ini dapat menyebabkan bug halus. Jauh lebih serius adalah poin Arturo di atas. Anda akan mengulangi waktu kamus yangdictionary.Count + 1
mengarah ke kompleksitas O (n ^ 2) untuk operasi yang seharusnya hanya O (n). Jika Anda benar-benar membutuhkan indeks (jika perlu, Anda mungkin menggunakan jenis koleksi yang salah sejak awal), Anda harus mengulanginyadictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value})
dan tidak menggunakan.ElementAt
di dalam loop.Tergantung pada apakah Anda setelah kunci atau nilai ...
Dari
Dictionary(TKey, TValue)
deskripsi Kelas MSDN :sumber
Secara umum, meminta "cara terbaik" tanpa konteks tertentu seperti bertanya apa warna terbaik ?
Di satu sisi, ada banyak warna dan tidak ada warna terbaik. Itu tergantung pada kebutuhan dan sering juga pada rasa.
Di sisi lain, ada banyak cara untuk beralih ke Kamus di C # dan tidak ada cara terbaik. Itu tergantung pada kebutuhan dan sering juga pada rasa.
Cara yang paling mudah
Jika Anda hanya membutuhkan nilainya (memungkinkan untuk memanggilnya
item
, lebih dapat dibaca daripadakvp.Value
).Jika Anda memerlukan urutan pengurutan tertentu
Secara umum, pemula terkejut tentang urutan enumerasi suatu Kamus.
LINQ menyediakan sintaksis ringkas yang memungkinkan untuk menentukan pesanan (dan banyak hal lainnya), misalnya:
Sekali lagi Anda mungkin hanya perlu nilai. LINQ juga menyediakan solusi ringkas untuk:
item
, lebih mudah dibaca daripadakvp.Value
)Ini dia:
Ada banyak lagi kasus penggunaan dunia nyata yang dapat Anda lakukan dari contoh-contoh ini. Jika Anda tidak memerlukan pesanan khusus, cukup ikuti "cara paling mudah" (lihat di atas)!
sumber
.Values
dan bukan klausa pilih.Value
bidang. Jenis yang tepat saya lihat di sini adalahIOrderedEnumerable<KeyValuePair<TKey, TValue>>
. Mungkin Anda bermaksud sesuatu yang lain? Bisakah Anda menulis baris lengkap yang menunjukkan apa yang Anda maksud (dan mengujinya)?items.Value
seperti yang Anda sarankan. Dalam kasus bagian keempat yang Anda komentari,Select()
ini adalah cara untuk menyebabkanforeach
penghitungan langsung pada nilai-nilai dalam kamus alih-alih pasangan nilai kunci. Jika Anda tidak sukaSelect()
dalam hal ini, Anda mungkin lebih suka bagian kode ketiga. Inti dari bagian keempat adalah untuk menunjukkan bahwa seseorang dapat melakukan pra-proses pengumpulan dengan LINQ..Keys.Orderby()
Anda akan mengulanginya pada daftar kunci. Jika itu yang Anda butuhkan, baiklah. Jika Anda membutuhkan nilai, maka dalam loop Anda harus menanyakan kamus pada setiap tombol untuk mendapatkan nilai. Dalam banyak skenario itu tidak akan membuat perbedaan praktis. Dalam skenario kinerja tinggi, itu akan terjadi. Seperti yang saya tulis di awal jawaban: "ada banyak cara (...) dan tidak ada cara terbaik. Itu tergantung pada kebutuhan dan sering juga pada selera."Saya akan mengatakan foreach adalah cara standar, meskipun itu jelas tergantung pada apa yang Anda cari
Itukah yang kamu cari?
sumber
kvp
umumnya digunakan untuk nama KeyValuePair contoh ketika iterasi kamus dan struktur data terkait:foreach(var kvp in myDictionary){...
.Anda juga dapat mencoba ini pada kamus besar untuk pemrosesan multithreaded.
sumber
C # 7.0 memperkenalkan Deconstructors dan jika Anda menggunakan .NET Core 2.0+ Application, struct
KeyValuePair<>
sudah menyertakan aDeconstruct()
untuk Anda. Jadi kamu bisa melakukan:sumber
foreach (var (key, value) in dic.Select(x => (x.Key, x.Value)))
Saya menghargai pertanyaan ini sudah memiliki banyak tanggapan tetapi saya ingin melakukan sedikit riset.
Iterasi pada kamus bisa agak lambat jika dibandingkan dengan iterasi pada sesuatu seperti array. Dalam pengujian saya, iterasi pada array membutuhkan waktu 0,015003 detik sedangkan iterasi pada kamus (dengan jumlah elemen yang sama) mengambil 0,0365073 detik, yang 2,4 kali lebih lama! Meskipun saya telah melihat perbedaan yang jauh lebih besar. Sebagai perbandingan, suatu Daftar berada di antara 0,00215043 detik.
Namun, itu seperti membandingkan apel dan jeruk. Maksud saya adalah iterasi kamus lebih lambat.
Kamus dioptimalkan untuk pencarian, jadi dengan itu dalam pikiran saya telah membuat dua metode. Satu hanya melakukan pendahuluan, yang lain iterates kunci kemudian melihat ke atas.
Yang ini memuat kunci dan beralih di atasnya (saya juga mencoba menarik kunci menjadi string [] tetapi perbedaannya dapat diabaikan.
Dengan contoh ini tes foreach normal mengambil 0,0310062 dan versi kunci mengambil 0,2205441. Memuat semua kunci dan mengulangi semua pencarian jelas BANYAK lebih lambat!
Untuk tes akhir saya telah melakukan iterasi saya sepuluh kali untuk melihat apakah ada manfaat menggunakan kunci di sini (pada titik ini saya hanya ingin tahu):
Inilah metode RunTest jika itu membantu Anda memvisualisasikan apa yang terjadi.
Di sini proses normal foreach memakan waktu 0,2820564 detik (sekitar sepuluh kali lebih lama dari iterasi tunggal - seperti yang Anda harapkan). Iterasi pada tombol mengambil 2,2249449 detik.
Diedit Untuk Menambahkan: Membaca beberapa jawaban lain membuat saya mempertanyakan apa yang akan terjadi jika saya menggunakan Kamus dan bukan Kamus. Dalam contoh ini array membutuhkan waktu 0,0120024 detik, daftar 0,0185037 detik dan kamus 0,0465093 detik. Masuk akal untuk berharap bahwa tipe data membuat perbedaan pada seberapa lambat kamus.
Apa Kesimpulan Saya ?
sumber
Ada banyak pilihan. Favorit pribadi saya adalah oleh KeyValuePair
Anda juga dapat menggunakan Koleksi Tombol dan Nilai
sumber
Dengan
.NET Framework 4.7
satu dapat menggunakan dekomposisiAgar kode ini berfungsi pada versi C # yang lebih rendah, tambahkan
System.ValueTuple NuGet package
dan tulis di suatu tempatsumber
ValueTuple
built-in. Ini tersedia sebagai paket nuget untuk versi sebelumnya. Lebih penting lagi, C # 7.0+ diperlukan agarDeconstruct
metode ini berfungsi sebagai dekonstruktorvar (fruit, number) in fruits
.Pada C # 7, Anda dapat mendekonstruksi objek menjadi variabel. Saya percaya ini menjadi cara terbaik untuk beralih ke kamus.
Contoh:
Buat metode ekstensi untuk
KeyValuePair<TKey, TVal>
mendekonstruksinya:Iterasi
Dictionary<TKey, TVal>
dengan cara berikutsumber
Anda menyarankan di bawah ini untuk beralih
FYI,
foreach
tidak berfungsi jika nilainya bertipe objek.sumber
foreach
tidak akan bekerja jika yang nilai adalah tipeobject
? Kalau tidak, ini tidak masuk akal.Bentuk paling sederhana untuk beralih ke kamus:
sumber
Dengan menggunakan C # 7 , tambahkan metode ekstensi ini ke proyek apa pun dari solusi Anda:
Dan gunakan sintaksis sederhana ini
Atau yang ini, jika Anda mau
Di tempat tradisional
Metode ekstensi mengubah
KeyValuePair
AndaIDictionary<TKey, TValue>
menjadi sangat diketiktuple
, memungkinkan Anda untuk menggunakan sintaks nyaman baru ini.Itu mengkonversi-hanya- entri kamus yang diperlukan untuk
tuples
, sehingga TIDAK mengubah seluruh kamustuples
, sehingga tidak ada masalah kinerja yang terkait dengan itu.Hanya ada sedikit biaya memanggil metode ekstensi untuk membuat
tuple
dibandingkan dengan menggunakanKeyValuePair
langsung, yang TIDAK boleh menjadi masalah jika Anda menetapkanKeyValuePair
propertiKey
danValue
variabel loop baru.Dalam praktiknya, sintaksis baru ini sangat cocok untuk sebagian besar kasus, kecuali untuk skenario kinerja ultra-tinggi tingkat rendah, di mana Anda masih memiliki opsi untuk tidak menggunakannya di tempat tertentu.
Lihat ini: Blog MSDN - Fitur baru di C # 7
sumber
kvp.Key
dankvp.Value
untuk menggunakan masing-masing kunci dan nilai. Dengan tuple Anda mendapatkan fleksibilitas untuk memberi nama kunci dan nilainya sesuai keinginan, tanpa menggunakan deklarasi variabel lebih lanjut di dalam blok foreach. Misalnya Anda dapat memberi nama kunci AndafactoryName
, dan nilainya sebagaimodels
, yang sangat berguna ketika Anda mendapatkan loop bersarang (kamus kamus): pemeliharaan kode menjadi lebih mudah. Cobalah! ;-)Saya tahu ini adalah pertanyaan yang sangat lama, tetapi saya membuat beberapa metode ekstensi yang mungkin berguna:
Dengan cara ini saya dapat menulis kode seperti ini:
sumber
Kadang-kadang jika Anda hanya perlu nilai untuk dihitung, gunakan koleksi nilai kamus:
Dilaporkan oleh pos ini yang menyatakan itu adalah metode tercepat: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html
sumber
Saya menemukan metode ini dalam dokumentasi untuk kelas DictionaryBase di MSDN:
Ini adalah satu-satunya yang saya bisa berfungsi dengan benar di kelas yang diwarisi dari DictionaryBase.
sumber
Hashtable
objekforeach
tercepat dan jika Anda hanya beralih___.Values
, itu juga lebih cepatsumber
ContainsKey()
dalamfor
versi? Itu menambah overhead tambahan yang tidak ada dalam kode yang Anda bandingkan.TryGetValue()
ada untuk mengganti pola "jika kunci ada, dapatkan item dengan kunci" yang tepat. Lebih lanjut, jikadict
berisi rentang bilangan bulat yang berdekatan dari0
hinggadictCount - 1
, Anda tahu pengindeks tidak dapat gagal; jika tidak,dict.Keys
adalah apa yang Anda harus iterasi. Either way, tidakContainsKey()
/TryGetValue()
dibutuhkan. Terakhir, tolong jangan memposting tangkapan layar kode.Saya akan memanfaatkan .NET 4.0+ dan memberikan jawaban yang diperbarui untuk yang diterima semula:
sumber
Cara standar untuk beralih ke Kamus, menurut dokumentasi resmi pada MSDN adalah:
sumber
Saya menulis ekstensi untuk mengulang kamus.
Maka Anda bisa menelepon
sumber
ForEach
metode di mana Anda memilikiforeach (...) { }
... Sepertinya tidak perlu.Jika mengatakan, Anda ingin mengulangi pengumpulan nilai secara default, saya yakin Anda dapat mengimplementasikan IEnumerable <>, Di mana T adalah jenis objek nilai dalam kamus, dan "ini" adalah Kamus.
sumber
Sebagaimana telah ditunjukkan pada jawaban ini ,
KeyValuePair<TKey, TValue>
mengimplementasikan aDeconstruct
metode yang dimulai pada .NET Core 2.0, .NET Standard 2.1 dan .NET Framework 5.0 (pratinjau).Dengan ini, dimungkinkan untuk beralih melalui kamus dengan
KeyValuePair
cara agnostik:sumber
sumber
AggregateObject
ditambahkanKeyValuePair
? Di mana "iterasi", seperti yang diminta dalam pertanyaan?foreach
, tetapi saya sudah sering menggunakannya. Apakah jawaban saya benar-benar layak untuk diturunkan?Select
gunakan iterasi untuk mempengaruhi hasil, tetapi bukan iterator itu sendiri. Jenis hal yangforeach
digunakan untuk iterasi ( ) - terutama operasi dengan efek samping - berada di luar ruang lingkup Linq, termasukSelect
. Lambda tidak akan berjalan sampaiaggregateObjectCollection
benar-benar disebutkan. Jika jawaban ini diambil sebagai "jalan pertama" (yaitu, digunakan sebelum garis lurusforeach
) itu mendorong praktik buruk. Secara situasional, mungkin ada operasi-operasi Linq yang membantu sebelum mengulang kamus, tetapi itu tidak menjawab pertanyaan sebagaimana ditanyakan.Hanya ingin menambahkan 2 sen saya, karena sebagian besar jawaban berkaitan dengan foreach-loop. Silakan lihat kode berikut:
Kalau dipikir-pikir ini menambahkan panggilan tambahan '.ToList ()', mungkin ada sedikit peningkatan kinerja (seperti yang ditunjukkan di sini foreach vs someList.Foreach () {} ), terutama ketika bekerja dengan Kamus besar dan berjalan secara paralel tidak ada option / tidak akan berpengaruh sama sekali.
Juga, harap dicatat bahwa Anda tidak dapat menetapkan nilai ke properti 'Nilai' di dalam foreach-loop. Di sisi lain, Anda akan dapat memanipulasi 'Kunci' juga, mungkin membuat Anda mendapat masalah saat runtime.
Saat Anda hanya ingin "membaca" Tombol dan Nilai, Anda mungkin juga menggunakan IEnumerable.Select ().
sumber
foreach
efek samping : memaksa visibilitas efek samping ke atas, di tempatnya.Kamus <TKey, TValue> Ini adalah kelas koleksi generik dalam c # dan menyimpan data dalam format nilai kunci. Kunci harus unik dan tidak boleh nol sedangkan nilai dapat digandakan dan null. Karena setiap item dalam kamus adalah diperlakukan sebagai struktur KeyValuePair <TKey, TValue> yang mewakili kunci dan nilainya. dan karenanya kita harus mengambil tipe elemen KeyValuePair <TKey, TValue> selama iterasi elemen. Di bawah ini adalah contohnya.
sumber
Jika Anda ingin menggunakan untuk loop, Anda dapat melakukan ini:
sumber
foreach
loop dan kinerja yang lebih buruk karenanew List<string>(dictionary.Keys)
akandictionary.Count
berulang kali bahkan sebelum Anda memiliki kesempatan untuk iterate sendiri. Mengesampingkan bahwa meminta "cara terbaik" adalah subyektif, saya tidak melihat bagaimana ini akan memenuhi syarat sebagai "cara terbaik" atau "cara standar" yang dicari oleh pertanyaan itu. Untuk "Jika Anda ingin menggunakan untuk loop ..." Saya akan membalas dengan " Jangan gunakanfor
loop."foreach (var pair in dictionary.ToArray()) { }
. Namun, saya pikir akan lebih baik untuk menjelaskan dalam skenario tertentu (s) di mana seseorang ingin menggunakan kode ini dan implikasi melakukannya.sederhana dengan LINQ
sumber
ToList()
karenaForEach()
hanya ditentukan padaList<>
kelas, tetapi mengapa melakukan semua itu, bukan hanyaforeach (var pair in dict) { }
? Saya akan mengatakan itu lebih sederhana dan tidak memiliki implikasi memori / kinerja yang sama. Solusi yang tepat ini sudah diusulkan dalam jawaban ini dari 3,5 tahun yang lalu.selain posting berperingkat tertinggi di mana ada diskusi antara menggunakan
atau
paling lengkap adalah yang berikut karena Anda bisa melihat jenis kamus dari inisialisasi, kvp adalah KeyValuePair
sumber