Soru Bir sözlük üzerinde yineleme yapmanın en iyi yolu nedir?


C # 'da bir sözlük üzerinde yinelemek için birkaç farklı yol gördüm. Standart bir yol var mı?


1949
2017-09-26 18:20


Menşei


Bu soruya bir çok kez cevap veren 923 kez cevapsız bir sürprizim var .. (foreach ofcourse) .. Tartışırım ya da en azından bir sözlük üzerinde yinelemeniz gerekiyorsa, şansınız var. yanlış / uygunsuz kullanarak .. Bu yorumu yapmak zorunda kaldım, çünkü IMHO'nun uygun olmadığı şekilde kötüye kullanılan sözlükleri kullandım ... Evet, sözlükten ziyade sözlüğü yineleyen nadir durumlar olabilir. Bu, bir sözlükte nasıl yineleneceğini merak etmeden önce lütfen aklınızda bulundurun. - Vikas Gupta
@VikasGupta Anahtarların ne olacağını bilmediğinizde, bir anahtar-değer çiftleri koleksiyonuyla ne yapmanız gerektiğini önerdiniz? - nasch
@nasch: myDictionary.Keys içinde anahtarları içeren bir koleksiyon verecek myDictionary. - displayName
@displayName Her bir anahtar / değer çiftiyle bir şeyler yapmak istiyorsanız, ancak değerlere bakmak için kullanacağınız tuşlara bir referansınız yoksa, sözlük üzerinde yineleyin, değil mi? Vikas'ın bunun genellikle yanlış kullanım olduğu iddiasına rağmen, bunu yapmak isteyeceğiniz zamanların olabileceğine işaret ediyordum. - nasch
Yanlış kullanımın daha iyi bir alternatif olduğunu ima ettiğini söylemek için. Bu alternatif nedir? - Kyle Delaney


Cevaplar:


foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

2902
2017-09-26 18:22



Sözlük'teki anahtar / değer türünü tam olarak bilmiyorsam ne olur? kullanma var entry bu durumda daha iyi ve böylece oy verdim bu cevap Yukarıdaki yerine ikinci bir bakışta. - Ozair Kafray
@OzairKafray kullanarak var tür bilmiyorsanız genellikle kötü bir uygulamadır. - Nate
Bu cevap üstündür çünkü Pablo, dönüş türünü gizleyen tembel kodlayıcı "var" kullanımına ön değer vermedi. - MonkeyWrench
@MonkeyWrench: Meh. Visual Studio, türün ne olduğunu bilir; Tek yapmanız gereken öğrenmek için değişkenin üzerine gelmektir. - Robert Harvey♦
Anladığım kadarıyla, var sadece tür derleme zamanında biliniyorsa çalışır. Visual Studio türünü bilirse, o zaman sizin de öğrenebilirsiniz. - Kyle Delaney


C # gibi bir jenerik sözlük kullanmaya çalışıyorsanız, başka bir dilde bir ilişkilendirici dizi kullanırdınız:

foreach(var item in myDictionary)
{
  foo(item.Key);
  bar(item.Value);
}

Ya da yalnızca anahtarların üzerinde yineleme yapmanız gerekiyorsa

foreach(var item in myDictionary.Keys)
{
  foo(item);
}

Ve son olarak, sadece değerlerle ilgileniyorsanız:

foreach(var item in myDictionary.Values)
{
  foo(item);
}

(Unutmayın ki var anahtar kelime isteğe bağlı bir C # 3.0 ve üstü özelliktir, ayrıca anahtarlarınızın / değerlerinin tam türünü de kullanabilirsiniz.


646
2017-09-26 18:22



var özelliği en çok ilk kod bloğunuz için gereklidir :) - nawfal
Bu cevabın, anahtarlar veya değerler üzerinde açıkça yineleyebileceğinizi belirttiğini takdir ediyorum. - Rotsiser Mho
Burada var kullanımını sevmiyorum. Sadece sözdizimsel şeker olduğu düşünüldüğünde, neden burada kullanıyorsunuz? Birisi kodu okumaya çalışırken, türünü belirlemek için kodun etrafında atlamak zorunda kalacaklar. myDictionary (tabii ki bu tabii ki adı değilse). Türün açık olduğu zaman var kullanmanın iyi olduğunu düşünüyorum. var x = "some string" ama hemen belli olmadığında, kod okuyucu / gözden geçiriciyi inciten tembel kodlama olduğunu düşünüyorum - James Wierzba
var Benim düşünceme göre, tutumlu kullanılmalıdır. Özellikle burada, yapıcı değil: tip KeyValuePair sorunun büyük olasılıkla alakalı. - Sinjai


Bazı durumlarda, döngü içi uygulama tarafından sağlanabilecek bir sayaca ihtiyacınız olabilir. Bunun için LINQ sağlar ElementAt Aşağıdakileri sağlar:

for (int index = 0; index < dictionary.Count; index++) {
  var item = dictionary.ElementAt(index);
  var itemKey = item.Key;
  var itemValue = item.Value;
}

107
2018-03-10 20:44



'.ElementAt' yöntemini kullanmak için şunu unutmayın: using System.Linq; Bu fx içinde değil. otomatik oluşturulan test sınıfları. - Tinia
Anahtarlarla ilişkili değerleri değiştiriyorsanız, bu yoldur. Aksi halde foreach () öğesini değiştirip kullanırken bir istisna atılır. - Mike de Klerk
Bunu kullanırken dikkatli olun. Buraya bakın: stackoverflow.com/a/2254480/253938 - RenniePet
değil ElementAt bir O (n) işlemi? - Arturo Torres Sánchez
Bu cevap, pek çok upvottan tamamen mahrumdur. Bir sözlüğün örtük bir sırası yoktur, bu yüzden .ElementAt Bu bağlamda ince hatalara yol açabilir. Çok daha ciddi olan Arturo'nın yukarıdaki noktası. Sözlüğü tekrarlayacaksınız dictionary.Count + 1 Sadece O (n) olması gereken bir işlem için O (n ^ 2) karmaşıklığına yol açan zamanlar. Gerçekten bir dizine ihtiyacınız varsa (ilk etapta muhtemelen yanlış toplama türünü kullanıyorsunuzdur), yinelemeniz gerekir dictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value}) yerine ve kullanmayın .ElementAt Döngü içinde. - spender


Anahtarların veya değerlerin peşinde olmanıza bağlıdır.

MSDN'den Dictionary(TKey, TValue) Sınıf açıklaması:

// 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);
}

75
2017-09-26 18:27





Genel olarak, belirli bir bağlam olmadan "en iyi yolu" sormak, en iyi rengin ne olduğunu sormak gibidir.

Bir yandan, birçok renk var ve en iyi renk yok. İhtiyaca ve genellikle tatlara da bağlıdır.

Öte yandan, C # 'da bir Sözlük üzerinde yinelemenin birçok yolu vardır ve en iyi yol yoktur. İhtiyaca ve genellikle tatlara da bağlıdır.

En basit yolu

foreach (var kvp in items)
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

Sadece değere ihtiyacınız varsa (buna izin verir) item, daha okunabilir kvp.Value).

foreach (var item in items.Values)
{
    doStuff(item)
}

Belirli bir sıralama düzenine ihtiyacınız varsa

Genel olarak, yeni başlayanlar bir Sözlükün numaralandırılması sırasına şaşırırlar.

LINQ, siparişi (ve diğer birçok şeyi) belirtmeyi sağlayan kısa bir sözdizimi sağlar, örn .:

foreach (var kvp in items.OrderBy(kvp => kvp.Key))
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

Yine sadece değere ihtiyacınız olabilir. LINQ ayrıca aşağıdakiler için özlü bir çözüm sunar:

  • Doğrudan değer üzerinde yineleme (buna izin verir item, daha okunabilir kvp.Value)
  • ancak tuşlara göre sıralanır

İşte burada:

foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value))
{
    doStuff(item)
}

Bu örneklerden yapabileceğiniz çok daha fazla gerçek dünya kullanım durumu var. Belirli bir siparişe ihtiyacınız yoksa, sadece “en basit yol” a (yukarıda) bakın!


55
2017-08-10 11:15



Sonuncusu olmalı .Values ve bir seçim cümlesi değil. - Mafii
@Mafii Emin misin? OrderBy tarafından döndürülen değerler, bir KeyValuePair türünde değildir; Value alan. Burada gördüğüm tam tip IOrderedEnumerable<KeyValuePair<TKey, TValue>>. Belki başka bir şey mi kastediyorsun? Ne demek istediğini gösteren tam bir çizgi yazabilir misin (ve test edebilirsin)? - Stéphane Gourichon
Bence bu cevap ne demek istediğimi içerir: stackoverflow.com/a/141105/5962841 ama bir şey karıştıysam beni düzelt - Mafii
@Mafii Bütün cevabımı tekrar oku, kod bölümleri arasındaki açıklamalar bağlamı anlatıyor. Bahsettiğiniz cevap cevabımdaki ikinci kod bölümü gibidir (sipariş gerekmez). Orada yeni yazdım items.Value önerdiğin gibi. Yorum yaptığınız dördüncü bölümün durumunda Select() neden olmanın bir yoludur foreach anahtar / değer çiftleri yerine doğrudan sözlükteki değerlerin numaralandırılması. Eğer bir şekilde beğenmediysen Select() Bu durumda üçüncü kod bölümünü tercih edebilirsiniz. Dördüncü bölümün amacı, koleksiyonun LINQ ile önceden işlenebileceğini göstermektir. - Stéphane Gourichon
Yaparsan .Keys.Orderby() Anahtarların bir listesi üzerinde yineleyin. Eğer ihtiyacın olan tek şey buysa, iyi. Değerlere ihtiyacınız varsa, döngüde değeri almak için her tuştaki sözlüğü sorgulamanız gerekir. Birçok senaryoda pratik bir fark yaratmayacaktır. Yüksek performanslı senaryoda, olacak. Cevabın başlangıcında yazmış olduğum gibi: "birçok yol var (...) ve en iyi yol yok. Bu ihtiyaçlara ve sık sık tatmaya da bağlı." - Stéphane Gourichon


Foreach'ın standart yol olduğunu söyleyebilirim;

foreach(var kvp in my_dictionary) {
  ...
}

Aradığın şey bu mu?


36
2017-09-26 18:22



Um, "değer" ibaresi çok kafa karıştırıcı değil mi? Genellikle "value.Key" ve "value.Value" gibi sözdizimi kullanıyorsunuz, bu kod okuyacak olan herkes için çok sezgisel değil, özellikle .Net Dictionary'in nasıl uygulandığını bilmiyorsanız . - RenniePet
@RenniePet kvp sözlükler ve ilgili veri yapıları üzerinde yineleme yaparken KeyValuePair örneklerini adlandırmak için yaygın olarak kullanılır: foreach(var kvp in myDictionary){.... - mbx


Bunu, çok iş parçacıklı işlem için büyük sözlüklerde de deneyebilirsiniz.

dictionary
.AsParallel()
.ForAll(pair => 
{ 
    // Process pair.Key and pair.Value here
});

28
2018-06-11 13:32



@WiiMaxx ve bu öğeler birbirine bağlı DEĞİL daha önemli - Mafii