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


2626

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


108
Ben bu soruya bir çok 923 kez ile birlikte birçok cevap vardır şaşırdım .. (foreach tabii ki kullanır) .. Ben tartışmak istiyorum, ya da en azından bir sözlük üzerinde tekrarlamak zorunda kalırsanız, şans vardır yanlış / uygunsuz kullanarak .. Bu yorumu yapmak zorunda kaldım, çünkü sözlüklerin IMHO'nun uygun olmadığı şekilde kötüye kullanıldığını gördüm ... Evet, sözlüğü yinelediğinizde, aramadan ziyade, nadiren de olabilir. bir sözlük üzerinde nasıl yineleneceğini merak etmeden önce lütfen aklınızda bulundurun.
Vikas Gupta

74
@VikasGupta Anahtarların ne olacağını bilmediğinizde, anahtar / değer çifti koleksiyonuyla bir şeyler yapmak için ne önerirsiniz?
nasch

26
@displayName Her bir anahtar / değer çiftiyle bir şeyler yapmak istiyorsanız, ancak değerleri aramak için kullanılacak tuşlara referansınız yoksa, sözlük üzerinde yineleme yaparsınız, değil mi? Vikas'ın bunun genellikle yanlış kullanım olduğu iddiasına rağmen, bunu yapmak isteyebileceğiniz zamanlar olabileceğini belirtiyordum.
Nasch

34
Yanlış kullanım olduğunu söylemek daha iyi bir alternatif olduğunu ima eder. Bu alternatif nedir?
Kyle Delaney

40
VikasGupta yanlış, teorik olmayan senaryolarda uzun yıllar yüksek performanslı C # ve C ++ programlamasından sonra doğrulayabilirim. Gerçekten, bir sözlük oluşturmak, benzersiz anahtar / değer çiftlerini depolamak ve daha sonra koleksiyon içinde benzersiz anahtarlara sahip olduğu kanıtlanmış bu değerler üzerinde yineleme yapmak için sık görülen durumlar vardır. Başka koleksiyonlar oluşturmak sözlük yinelemesinden kaçınmanın gerçekten verimsiz ve maliyetli bir yoludur. Lütfen bakış açınızı açıklayan soruya cevap olarak iyi bir alternatif sağlayın, aksi takdirde yorumunuz oldukça saçmadır.
sɐunıɔ ןɐ qɐp

Yanıtlar:


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

29
Sözlük'teki anahtar / değer türünü tam olarak bilmiyorsam ne olur? var entryBu durumda kullanmak daha iyidir ve bu yüzden bu cevabı yukarıdaki yerine ikinci bir bakışta oyladım.
Ozair Kafray

93
@OzairKafray kullanarak vartürü bilmiyorsanız genellikle kötü bir uygulamadır.
Nate

52
Bu cevap üstündür çünkü Pablo, dönüş türünü gizleyen tembel kodlayıcı "var" kullanımını varsayılan olarak kullanmadı.
MonkeyWrench

119
@MonkeyWrench: Meh. Visual Studio, türün ne olduğunu bilir; tek yapmanız gereken bulmak için değişkenin üzerine gelin.
Robert Harvey

31
Anladığım kadarıyla, varyalnızca tür derleme zamanında biliniyorsa çalışır. Visual Studio türü biliyorsa, o zaman sizin de öğrenebilirsiniz.
Kyle Delaney

866

C # 'da genel bir Sözlük kullanmaya çalışıyorsanız, başka bir dilde ilişkilendirilebilir bir dizi kullanırsınız:

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

Veya yalnızca anahtar toplama işlemi üzerinde yineleme yapmanız gerekiyorsa,

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

Son olarak, yalnızca değerlerle ilgileniyorsanız:

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

( varAnahtar kelimenin isteğe bağlı C # 3.0 ve üstü bir özellik olduğunu unutmayın, burada anahtarlarınızın / değerlerinizin tam türünü de kullanabilirsiniz)


11
var özelliği ilk kod bloğunuz için en çok gereklidir :)
nawfal

27
Bu cevabın, anahtarlar veya değerler üzerinde açıkça tekrar edebileceğinizi belirtmek isterim.
Rotsiser Mho

11
Burada var kullanımını sevmiyorum. Sadece sözdizimsel şeker olduğu göz önüne alındığında, neden burada kullanıyorsunuz? Birisi kodu okumaya çalışırken, türünü belirlemek için kodun etrafında atlamak zorunda kalacaktır myDictionary(tabii ki gerçek isim değilse). Ben tür örneğin açık olduğunda var kullanmanın iyi olduğunu düşünüyorum var x = "some string"ama hemen belli olmadığı zaman ben kod okuyucu / gözden geçiren acı tembel kodlama düşünüyorum
James Wierzba

8
varbence, idareli kullanılmalıdır. Özellikle burada, yapıcı değildir: tür KeyValuePairmuhtemelen soru ile ilgilidir.
Sinjai

3
varbenzersiz bir amacı var ve 'sözdizimsel' şeker olduğuna inanmıyorum. Bunu kasten kullanmak uygun bir yaklaşımdır.
Joshua K

159

Bazı durumlarda, for-loop uygulaması tarafından sağlanabilecek bir sayaca ihtiyacınız olabilir. Bunun için LINQ ElementAtaş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;
}

21
'.ElementAt' yöntemini kullanmak için şunu unutmayın: using System.Linq; Bu fx'e dahil değildir. otomatik oluşturulan test sınıfları.
Tinia

14
Anahtarlarla ilişkili değerleri değiştiriyorsanız, bu yöntem de kullanılabilir. Aksi takdirde, foreach () değiştirilirken ve kullanılırken bir istisna atılır.
Mike de Klerk

27
Is not ElementAtbir O (n) işlemi?
Arturo Torres Sánchez

162
Bu cevap birçok upvote'u tamamen hak etmiyor. Bir sözlüğün örtülü bir sırası yoktur, bu nedenle .ElementAtbu bağlamda kullanmak küçük hatalara yol açabilir. Arturo'nun yukarıdaki noktası çok daha ciddi. Yalnızca dictionary.Count + 1O (n) olması gereken bir işlem için O (n ^ 2) karmaşıklığına yol açan sözlük sürelerini yineleyeceksiniz . Gerçekten bir dizine ihtiyacınız varsa (eğer öyleyse, muhtemelen ilk etapta yanlış toplama türünü kullanıyorsunuz), dictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value})bunun yerine yinelemelisiniz ve .ElementAtdöngü içinde kullanmamalısınız .
harcı

5
ElementAt - o (n) işlemi! Ciddi anlamda? Bunu nasıl yapmamanız gerektiğine dair bir örnek. Bu kadar upvotes var mı?
Mukesh Adhvaryu

96

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

MSDN'den Dictionary(TKey, TValue) Class açıklamasından:

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

82

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

Bir yandan, birçok renk var ve en iyi renk yok. İhtiyaca ve çoğu zaman da tada bağlıdır.

Öte yandan, bir Sözlük üzerinde C # yineleme birçok yolu vardır ve en iyi yolu yoktur. İhtiyaca ve çoğu zaman da tada bağlıdır.

En kolay yol

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üğün numaralandırma sırası konusunda şaşırırlar.

LINQ, siparişi (ve diğer birçok şeyi) belirtmenize izin veren özlü bir sözdizimi sağlar;

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ğıdakilere kısa bir çözüm sunar:

  • doğrudan değer üzerinde yineleme (onu çağırmaya izin verir item, daha okunabilir kvp.Value)
  • ama anahtarlara göre sıralandı

İşte burada:

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

Bu örneklerden yapabileceğiniz daha birçok gerçek dünya kullanım durumu vardır. Belirli bir siparişe ihtiyacınız yoksa, "en basit yol" a sadık kalın (yukarıya bakın)!


Sonuncusu .Valuesbir seçme cümlesi değil, olmalıdır .
Mafii

@Mafii Emin misin? OrderBy tarafından döndürülen değerler KeyValuePair türünde değil, Valuealanı yok . Burada gördüğüm kesin tip IOrderedEnumerable<KeyValuePair<TKey, TValue>>. Belki başka bir şey mi demek istediniz? Ne demek istediğinizi gösteren tam bir satır yazabilir misiniz (ve test edin)?
Stéphane Gourichon

Bence bu cevap ne demek istediğimi içeriyor: stackoverflow.com/a/141105/5962841 ama kafam
karıştıysa

1
@Mafii Tüm cevabımı tekrar oku, kod bölümleri arasındaki açıklamalar içeriği anlatıyor. Bahsettiğiniz cevap, cevabımdaki ikinci kod bölümü gibidir (sipariş gerekli değildir). Orada items.Valueönerdiğin gibi yazdım . Yorum yaptığınız dördüncü bölüm söz konusu Select()olduğunda foreach, anahtar / değer çiftleri yerine doğrudan sözlükteki değerleri numaralandırmanın bir yoludur . Select()Bu durumda bir şekilde hoşlanmıyorsanız , üçü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

1
Bunu yaparsanız .Keys.Orderby()bir anahtar listesi üzerinde yineleyeceksiniz. İhtiyacın olan tek şey buysa, tamam. Değerlere ihtiyacınız varsa, döngüde değeri elde etmek için her bir anahtardaki sözlüğü sorgulamanız gerekir. Birçok senaryoda pratik bir fark yaratmaz. Yüksek performanslı senaryoda olacak. Cevabın başında yazdığım gibi: "pek çok yol var (...) ve en iyi yol yok. İhtiyaca ve çoğu zaman da tada bağlı."
Stéphane Gourichon

53

Açıkçası aradığınız şeye bağlı olsa da, foreach standart bir yol olduğunu söyleyebilirim

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

Aradığın şey bu mu?


42
"Değeri" olarak adlandırmak oldukça kafa karıştırıcı değil mi? Genellikle "value.Key" ve "value.Value" gibi bir sözdizimi kullanırsınız. .
RenniePet

3
@RenniePet kvpyaygın KeyValuePair örneklerini tarif etmek için kullanılmaktadır ilerlerken sözlük ve ilgili veri yapıları üzerinde: foreach(var kvp in myDictionary){....
mbx

37

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

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

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

36

C # 7.0 Deconstructors tanıttı ve .NET Core 2.0+ uygulamakullanıyorsanız, yapıKeyValuePair<>zatenDeconstruct()sizin içinbir içerir. Böylece şunları yapabilirsiniz:

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

resim açıklamasını buraya girin


5
En azından foreach (var (key, value) in dic.Select(x => (x.Key, x.Value)))
4.7.2'ye

29

Bu sorunun zaten çok fazla cevabı olduğunu takdir ediyorum ama biraz araştırma yapmak istedim.

Bir sözlük üzerinden yineleme, dizi gibi bir şey üzerinde yineleme ile karşılaştırıldığında oldukça yavaş olabilir. Testlerimde, bir dizi üzerindeki bir yineleme 0.015003 saniye sürerken, bir sözlük üzerindeki bir yineleme (aynı sayıda elemanla), 2.4365073 saniye sürdü, bu da 2.4 kat daha uzun! Çok daha büyük farklar görmeme rağmen. Karşılaştırma için bir Liste 0.00215043 saniyede bir yerdeydi.

Ancak, bu elma ve portakalları karşılaştırmak gibidir. Demek istediğim, sözlükler üzerinde yineleme yapmak yavaş.

Sözlükler aramalar için optimize edilmiştir, bu nedenle iki yöntem geliştirdim. Biri sadece bir foreach yapar, diğeri anahtarları tekrarlar ve sonra bakar.

public static string Normal(Dictionary<string, string> dictionary)
{
    string value;
    int count = 0;
    foreach (var kvp in dictionary)
    {
        value = kvp.Value;
        count++;
    }

    return "Normal";
}

Bu bir anahtarları yükler ve bunun yerine yineliyor (Ben de bir [[] anahtarları çekmeye çalıştım ama fark ihmal edilebilir.

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";
}

Bu örnekle normal foreach testi 0.0310062 ve anahtar versiyonu 0.2205441 aldı. Tüm anahtarları yüklemek ve tüm aramalar üzerinde yineleme yapmak çok daha yavaştır!

Son bir test için, burada anahtarları kullanmanın herhangi bir faydası olup olmadığını görmek için on kez yinelememi gerçekleştirdim (bu noktaya kadar sadece merak ettim):

Olanları görselleştirmenize yardımcı oluyorsa RunTest yöntemi şöyledir.

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

Burada normal foreach koşusu 0.2820564 saniye sürdü (beklediğiniz gibi tek bir yinelemeden yaklaşık on kat daha uzun). Anahtarların yinelenmesi 2.2249449 saniye sürdü.

Eklemek İçin Düzenlendi: Diğer cevapların bazılarını okumak, Sözlük yerine Sözlük kullanırsam ne olacağını sorgulamamı sağladı. Bu örnekte dizi 0.0120024 saniye, liste 0.0185037 saniye ve sözlük 0.0465093 saniye sürdü. Veri türünün, sözlüğün ne kadar yavaş olduğu konusunda bir fark yaratmasını beklemek mantıklıdır.

Sonuçlarım nelerdir?

  • Mümkünse bir sözlük üzerinden yinelemekten kaçının, içinde aynı veri bulunan bir dizi üzerinden yinelemekten çok daha yavaştırlar.
  • Bir sözlük üzerinden yineleme yapmayı seçerseniz, çok zeki olmaya çalışmayın, daha yavaş olmasına rağmen standart foreach yöntemini kullanmaktan çok daha kötü yapabilirsiniz.

11
DateTime yerine StopWatch gibi bir şeyle ölçmelisiniz
Hatta Mien

2
Eğer test senaryosu, sözlükte kaç madde, ortalama zaman hesaplamak için senaryonuzu ne sıklıkta çalıştırdınız, lütfen tarif edebilir misiniz ...
WiiMaxx

3
İlginçtir, sözlükte hangi verilere sahip olduğunuza bağlı olarak farklı sonuçlar elde edersiniz. Sözlük üzerinde yineleme yaparken, numaralandırıcı işlevi sözlükte bir dizi boş alanı atlamak zorundadır, bu da bir dizi üzerinde yinelemekten daha yavaş olmasına neden olur. Sözlük doluysa, atlamak için yarı boş olandan daha az boş alan olacaktır.
Martin Brown

26

Birçok seçenek var. Kişisel favorim KeyValuePair tarafından

Dictionary<string, object> myDictionary = new Dictionary<string, object>();
// Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary)
{
     // Do some interesting things
}

Anahtarlar ve Değerler Koleksiyonlarını da kullanabilirsiniz


14

.NET Framework 4.7Biri ile ayrışma kullanabilirsiniz

var fruits = new Dictionary<string, int>();
...
foreach (var (fruit, number) in fruits)
{
    Console.WriteLine(fruit + ": " + number);
}

Bu kodun daha düşük C # sürümlerinde çalışmasını sağlamak için bir System.ValueTuple NuGet packageyere ekleyin ve yazın

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

9
Bu yanlış. .NET 4.7 basitçe ValueTupleyerleşiktir. Önceki sürümler için bir nuget paketi olarak kullanılabilir. Daha da önemlisi, Deconstructyöntemin bir yapısökücü olarak çalışması için C # 7.0+ gereklidir var (fruit, number) in fruits.
David Arno

13

C # 7'den itibaren, nesneleri değişkenler halinde yapılandırabilirsiniz. Bunun bir sözlük üzerinden yinelemenin en iyi yolu olduğuna inanıyorum.

Misal:

KeyValuePair<TKey, TVal>Bu yapıyı bozan bir uzantı yöntemi oluşturun :

public static void Deconstruct<TKey, TVal>(this KeyValuePair<TKey, TVal> pair, out TKey key, out TVal value)
{
   key = pair.Key;
   value = pair.Value;
}

Dictionary<TKey, TVal>Aşağıdaki şekilde yineleyin

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

10

Tekrarlamak için aşağıda önerdin

Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary) {
    //Do some interesting things;
}

FYI, foreachdeğer type nesnesiyse çalışmaz.


4
Lütfen detaylandırın: hangi değer türdeyse foreachçalışmaz ? Aksi takdirde bu pek mantıklı değil. object
Marc L.

9

Bir sözlüğü yinelemek için en basit form:

foreach(var item in myDictionary)
{ 
    Console.WriteLine(item.Key);
    Console.WriteLine(item.Value);
}

9

C # 7 kullanarak , bu uzantı yöntemini çözümünüzün herhangi bir projesine ekleyin:

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


Ve bu basit sözdizimini kullanın

foreach (var(id, value) in dict.Tuples())
{
    // your code using 'id' and 'value'
}


Veya bu, eğer isterseniz

foreach ((string id, object value) in dict.Tuples())
{
    // your code using 'id' and 'value'
}


Geleneksel yerine

foreach (KeyValuePair<string, object> kvp in dict)
{
    string id = kvp.Key;
    object value = kvp.Value;

    // your code using 'id' and 'value'
}


Uzatma yöntemi dönüştüren KeyValuePair, aramalarınızdan IDictionary<TKey, TValue>kesinlikle yazılı içine tuplebu yeni konforlu sözdizimini kullanmak için izin.

-Just- gerekli sözlük girişlerini tuplesdönüştürür tuples, bu yüzden tüm sözlüğü dönüştürmez , dolayısıyla bununla ilgili performans kaygısı yoktur.

Doğrudan tuplekullanarak karşılaştırmak için bir genişletme yöntemi çağıran sadece küçük bir maliyet KeyValuePairvardır, KeyValuePair's özellikleri Keyve Valueyine de yeni döngü değişkenleri atarsanız bir sorun OLMAMALIDIR .

Pratikte, bu yeni sözdizimi, hala belirli bir noktada kullanmama seçeneğiniz olan düşük seviyeli ultra yüksek performans senaryoları dışında çoğu durum için çok uygundur.

Şuna göz atın: MSDN Blog - C # 7'deki yeni özellikler


1
Anahtar / değer çifti çiftlerine 'rahat' tuples'i tercih etmenin nedeni ne olurdu? Burada bir kazanç görmüyorum. Grubunuz bir anahtar ve bir değer içerir, anahtar / değer çifti de içerir.
Maarten

4
Merhaba Maarten, sorunuz için teşekkürler. Ana avantaj, ek programlama çabası olmadan kod okunabilirliğidir. KeyValuePair ile her zaman form kullanılmalı kvp.Keyve kvp.Valuesırasıyla anahtar ve değer kullanılmalıdır. Tuples ile, foreach bloğunun içinde başka değişken bildirimleri kullanmadan anahtarı ve değeri istediğiniz gibi adlandırma esnekliği elde edersiniz. Örneğin, anahtarınızı şu şekilde adlandırabilirsiniz: factoryNameve değeri models, özellikle iç içe döngüler (sözlüklerin sözlükleri) aldığınızda yararlıdır: kod bakımı çok daha kolay hale gelir. Sadece bir deneyin! ;-)
sɐunıɔ ןɐ qɐp

7

Bunun çok eski bir soru olduğunu biliyorum, ancak yararlı olabilecek bazı uzantı yöntemleri oluşturdum:

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

Bu şekilde böyle bir kod yazabilirsiniz:

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

6

Bazen yalnızca numaralandırılması gereken değerlere ihtiyacınız varsa, sözlüğün değer toplamasını kullanın:

foreach(var value in dictionary.Values)
{
    // do something with entry.Value only
}

En hızlı yöntem olduğunu belirten bu yazı tarafından bildirildi: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html


Performansı getirmek için +1. Gerçekten de, sözlükte tek başına yineleme yapmak, ihtiyacınız olan her şey değerse bazı ek yükler içerir. Bunun nedeni genellikle değerleri veya başvuruları KeyValuePair yapılarına kopyalamadır.
Jaanus Varus

1
Bu bağlantıdaki son test yanlış şeyi test etmektir: değerleri göz ardı ederek tuşlar üzerinde yinelemeyi ölçer, oysa önceki iki test değeri kullanır.
Crescent Fresh

5

Bu yöntemi MSDN'de DictionaryBase sınıfının belgelerinde buldum:

foreach (DictionaryEntry de in myDictionary)
{
     //Do some stuff with de.Value or de.Key
}

DictionaryBase'den devralınan bir sınıfta düzgün çalışabildiğim tek kişi buydu.


3
Bu, sözlüğün jenerik olmayan sürümünü kullanırken (ör. .NET framework 2.0'dan önce) gibi görünür.
joedotnot

@ joed0tnot: Hashtablenesneler için kullanılan jenerik olmayan bir sürümdür
sɐunıɔ ןɐ qɐp

5

foreachen ___.Valueshızlıdır ve yalnızca yineleme yaparsanız , daha hızlıdır

resim açıklamasını buraya girin


Neden arıyorsun ContainsKey()içinde forsürümüne? Bu, karşılaştırdığınız kodda bulunmayan fazladan ek yük getirir. TryGetValue()"anahtar varsa, öğeyi anahtarla al" deseninin yerini almak için vardır. Bundan başka, eğer dictgelen tamsayılar bitişik bir dizi içerir 0için dictCount - 1, dizinleyici başarısız olamaz biliyorum; aksi halde dict.Keysyinelemeniz gereken şey budur. Her iki şekilde de, hayır ContainsKey()/ TryGetValue()gerekli. Son olarak, lütfen kodun ekran görüntülerini göndermeyin.
BACON

3

.NET 4.0+ avantajından yararlanacağım ve orijinal olarak kabul edilene güncel bir cevap vereceğim:

foreach(var entry in MyDic)
{
    // do something with entry.Value or entry.Key
}

3

MSDN'deki resmi belgelere göre bir Sözlük üzerinden yineleme yapmanın standart yolu:

foreach (DictionaryEntry entry in myDictionary)
{
     //Read entry.Key and entry.Value here
}

2

Bir sözlük üzerinde döngü için bir uzantı yazdım.

public static class DictionaryExtension
{
    public static void ForEach<T1, T2>(this Dictionary<T1, T2> dictionary, Action<T1, T2> action) {
        foreach(KeyValuePair<T1, T2> keyValue in dictionary) {
            action(keyValue.Key, keyValue.Value);
        }
    }
}

Sonra arayabilirsin

myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));

Sahip olduğunuz bir ForEachyöntemi tanımladınız foreach (...) { }... Gereksiz gibi görünüyor.
Maarten

1

Eğer diyelim, varsayılan olarak değerler koleksiyonu üzerinde yineleme yapmak istiyorsanız, IEnumerable <> uygulayabileceğinize inanıyorum, burada T sözlükteki değerler nesnesinin türüdür ve "this" bir Sözlüktür.

public new IEnumerator<T> GetEnumerator()
{
   return this.Values.GetEnumerator();
}

1

Sadece en çok cevap foreach-loop ile ilgili olarak, benim 2 cent eklemek istedim. Lütfen aşağıdaki koda bir göz atın:

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

Bu '.ToList ()' bir ek çağrıyı ekler altought (belirttiği gibi burada hafif bir performans iyileştirme olabilir someList.Foreach () {} vs foreach , büyük Sözlükler ile çalışan ve paralel çalışan espacially zaman hayır) seçeneğinin hiç etkisi olmaz.

Ayrıca, foreach döngüsü içindeki 'Değer' özelliğine değer atayamayacağınızı lütfen unutmayın. Öte yandan, 'Anahtar'ı da manipüle edebileceksiniz, muhtemelen çalışma zamanında başınızı belaya sokacaksınız.

Anahtarları ve Değerleri sadece "okumak" istediğinizde, IEnumerable.Select () öğesini de kullanabilirsiniz.

var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );

5
Hiç sebepsiz tüm koleksiyonu Kopyalama olacak değil performansını artırmak. Neredeyse ek bellek tüketmemesi gereken kodun bellek ayak izini iki katına çıkarmanın yanı sıra kodu önemli ölçüde yavaşlatır.
Servy

Yan etki 'List.ForEach' yönteminden kaçınırım: foreachyan etki görünürlüğünü ait olduğu yere kadar zorlar.
user2864740

0
var dictionary = new Dictionary<string, int>
{
    { "Key", 12 }
};

var aggregateObjectCollection = dictionary.Select(
    entry => new AggregateObject(entry.Key, entry.Value));

2
Bu cevapta daha fazla gerekçe / açıklama olması gerekiyor. Ne AggregateObjectekler KeyValuePair? Soruda istendiği gibi "yineleme" nerede?
Marc L.

Seç sözlük üzerinden yineleme yapar ve her nesne üzerinde çalışmamıza izin verir. Bu kadar genel değil foreach, ama çok kullandım. Cevabım gerçekten inmeyi hak etti mi?
Pixar

Hayır, sonucu etkilemek için yinelemeyi Select kullanır , ancak yineleyicinin kendisi değildir. Yineleme ( foreach) için kullanılan şey türleri - özellikle yan etkileri olan işlemler - Linq'in kapsamı dışındadır Select. Lambda aggregateObjectCollectionaslında numaralandırılana kadar koşmayacak . Eğer bu cevap bir "ilk yol" olarak alınırsa (yani bir düzlükten önce kullanılırsa foreach) kötü uygulamaları teşvik eder. Durumsal olarak, bir sözlüğü tekrarlamadan önce yardımcı olan , ancak soruyu sorulduğu gibi ele almayan Linq işlemleri olabilir .
Marc L.

0

Sözlük <TKey, TValue> Bu c # genel bir toplama sınıfıdır ve verileri anahtar / değer biçiminde saklar.Anahtar benzersiz olmalı ve değer olmamalı, değer yinelenebilir ve null olabilir. Sözlükteki her öğe olduğu gibi bir anahtarı ve değerini temsil eden KeyValuePair <TKey, TValue> yapısı olarak kabul edilir. ve dolayısıyla elemanın yinelemesi sırasında KeyValuePair <TKey, TValue> eleman tipini almalıyız. Aşağıda örnek.

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

0

Döngü için kullanmak istiyorsanız, bunu yapabilirsiniz:

var keyList=new List<string>(dictionary.Keys);
for (int i = 0; i < keyList.Count; i++)
{
   var key= keyList[i];
   var value = dictionary[key];
 }

Ancak bunun yararı nedir? Bu bir uzun kod var foreachdöngü ve çünkü kötü bir performans new List<string>(dictionary.Keys)yineleme olacak dictionary.Counthatta kendin yineleme şansı önce kez. "En iyi yolu" istemenin öznel olduğunu bir kenara bırakarak, sorunun nasıl "en iyi yol" veya "standart yol" olarak nitelendirileceğini görmüyorum. "Eğer döngü için kullanmak istiyorsanız ..." Kime ı ile karşı koyacaktır " Do not bir kullanmak fordöngü."
BACON

Büyük koleksiyonunuz varsa ve işlemler her zaman yavaşsa ve koleksiyonunuz yinelediğinizde değişebiliyorsa, sizi "koleksiyon değişti" hatasından korur ve bu çözüm ElementAt kullanarak daha iyi performans gösterir.
Seçkin Durgay

"Koleksiyon değiştirildi" istisnalarından kaçınmanın bunu yapmanın bir nedeni olduğunu kabul ediyorum, ancak bu özel durum soruda belirtilmedi ve biri her zaman yapabilirdi foreach (var pair in dictionary.ToArray()) { }. Yine de, cevapta birinin bu kodu kullanmak isteyeceği belirli senaryo (ları) ve bunu yapmanın sonuçlarını açıklığa kavuşturmanın iyi olacağını düşünüyorum.
BACON

evet haklısın ama ElementAt ile bir cevap var ve çok yüksek bir itibara sahip ve bu cevaba
girdim

-1

linq ile basit

 Dictionary<int, string> dict = new Dictionary<int, string>();
 dict.Add(1, "American Ipa");
 dict.Add(2, "Weiss");
 dict.ToList().ForEach(x => Console.WriteLine($"key: {x.Key} | value: {x.Value}") );

Görüyorsunuz ToList()çünkü ForEach()sadece List<>sınıfta tanımlanmışsınız , ama neden sadece bunun yerine bunu yapıyorsunuz foreach (var pair in dict) { }? Bunun daha da basit olduğunu ve aynı bellek / performans sonuçları olmadığını söyleyebilirim. Bu kesin çözüm zaten 3.5 yıl önceki bu cevapta önerilmişti .
BACON

Sadece kod görselleştirme uğruna, gerçekten belirttiğiniz şekilde yapılabilir, sadece farklı bir şekilde sunmak istedim ve yalın görüşüme göre, belirtilen cevabı görmediğiniz için özür dilerim, bir sarılmak
Luiz Fernando Corrêa Leite

-3

kullanma arasında bir tartışma olduğu en yüksek dereceli gönderilere ek olarak

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

veya

foreach(var entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

başlatma işleminden sözlük türünü görebildiğiniz için en eksiksiz olan aşağıdaki, 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
}

5
İkinci bir sözlük oluşturmak ve kopyalamak, kod okunabilirliği için geçerli bir çözüm değildir. Aslında, kodun anlaşılmasını zorlaştıracağını iddia ediyorum çünkü şimdi kendinize sormanız gerekiyor: "Son adam neden ikinci bir sözlük yarattı?" Daha ayrıntılı olmak istiyorsanız, birinci seçeneği kullanın.
Matthew Goulart

Ben sadece size daha önce her biri için decl dikt zaman, foreach kullanımı deklarasyondan açık olduğunu göstermek
istedim
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.