Sözlüğe eklemenin farklı yolları


107

Farkı nedir Dictionary.add(key, value)ve Dictionary[key] = value?

ArgumentExceptionYinelenen bir anahtar eklerken son sürümün bir atmadığını fark ettim , ancak ilk sürümü tercih etmek için herhangi bir neden var mı?

Düzenleme : Bu konuda yetkili bir bilgi kaynağına sahip olan var mı? MSDN'i denedim, ancak her zamanki gibi vahşi bir kaz avı :(

Yanıtlar:


109

Performans neredeyse% 100 aynıdır. Reflector.net'te sınıfı açarak bunu kontrol edebilirsiniz.

Bu, bu indeksleyicidir:

public TValue this[TKey key]
{
    get
    {
        int index = this.FindEntry(key);
        if (index >= 0)
        {
            return this.entries[index].value;
        }
        ThrowHelper.ThrowKeyNotFoundException();
        return default(TValue);
    }
    set
    {
        this.Insert(key, value, false);
    }
}

Ve bu, Add yöntemidir:

public void Add(TKey key, TValue value)
{
    this.Insert(key, value, true);
}

Oldukça uzun olduğu için tüm Insert metodunu göndermeyeceğim, ancak metot bildirimi şudur:

private void Insert(TKey key, TValue value, bool add)

Ve fonksiyonun ilerleyen kısımlarında bu gerçekleşir:

if ((this.entries[i].hashCode == num) && this.comparer.Equals(this.entries[i].key, key))
{
    if (add)
    {
        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
    }

Anahtarın zaten var olup olmadığını kontrol eder ve eğer varsa ve add parametresi true ise, istisnayı atar.

Yani tüm amaçlar ve niyetler için performans aynıdır.

Diğer birkaç söz gibi, her şey aynı anahtarı iki kez ekleme girişimleri için kontrole ihtiyacınız olup olmadığı ile ilgilidir.

Uzun gönderi için özür dilerim, umarım sorun olmaz.


+1 Çok ilginç, gönderiniz için teşekkürler! O performansı diğer afişler hakkında ipuçları veriyorlar olarak, burada hemen hemen aynıdır zaten büyük bulmak :) görünüyor
Sune Rievers

70

İlk sürüm, sözlüğe yeni bir KeyValuePair ekleyecek ve anahtar zaten sözlükte ise atacaktır. İkincisi, indeksleyiciyi kullanarak, anahtar yoksa yeni bir çift ekler, ancak sözlükte zaten varsa anahtarın değerinin üzerine yazar.

IDictionary<string, string> strings = new Dictionary<string, string>();

strings["foo"] = "bar";          //strings["foo"] == "bar"
strings["foo"] = string.Empty;   //strings["foo"] == string.empty
strings.Add("foo", "bar");       //throws     

+1 Yukarıdaki bilgiler için bir kaynağınız var mı? Birinci veya ikinci formu kullanırken herhangi bir yan etki veya uyarı olup olmadığını öğrenmekle ilgileniyorum.
Sune Rievers

3
Kafamın tepesinde gerçekten böyle bir kaynağa sahip değilim, ancak diğer yorumlarda belirtilenden çok daha fazlası olduğunu sanmıyorum. Doğru hatırlıyorsam, Ekle sadece indeksleyiciyi kullanır, ancak önce Anahtarın kullanımda olup olmadığını kontrol eder.
hhravn

1
Steffen'in cevabı değiştirildi, çünkü belgeleri birinci sınıf. Yine de bu harika bir cevap.
Sune Rievers

@Sune: Kötü hareket ... Şahsen bu cevabın Steffen'in sokaklarında olduğunu düşünüyorum ... doğrudan konuya ve iyi bir örnek.
demoncodemonkey

1
@SuneRievers Bence mevcut cevap yerine bunun cevabı kabul edilirse insanlar için daha faydalı olacak. Bu, kabul edilen sorudan ("fark nedir") tam olarak yanıtladığı için (bu, performans hakkında konuşuyor ve bu konuyu arayan kullanıcıların neredeyse% 99'u (benim gibi) "farka" ihtiyaç duyuyordu (bununla neden karşılaştım konu) ve kabul edilen cevap benim için faydasızdı ve
ikincimizi boşa harcıyor

30

Dictionary.Add(key, value)ve Dictionary[key] = valuefarklı amaçları vardır:

  • Yeni anahtar / değer çifti eklemek için Addyöntemi kullanın , mevcut anahtarlar değiştirilmeyecektir (bir atılır).ArgumentException
  • Anahtarın sözlükte bulunup bulunmadığını önemsemiyorsanız dizin oluşturucuyu kullanın, başka bir deyişle: anahtar sözlükte değilse anahtar / değer çiftini ekleyin veya anahtar zaten varsa belirtilen anahtarın değerini değiştirin sözlükte.

1
Niyeti kendi kendine tanımlayan kod önemlidir ve son derece değerlidir (ve çok az veya hiç yorum gerektirmez). Bu cevap, her iki yöntemle niyet arasındaki farkı gösterir ve birini seçerken izlenmelidir. Başka bir deyişle, önceden her zaman eklemeyi veya her zaman eklemeniz gerektiğini bildiğiniz zaman 'dizin oluşturucu ekleme' özelliğini kullanmayın . Bir IndexOutOfBounds özel durumunun oluşması beklenmeyen davranıştan daha iyidir.
ryancdotnet

28

Soruyu cevaplamak için önce bir sözlüğün amacına ve altında yatan teknolojiye bakmamız gerekir.

DictionaryKeyValuePair<Tkey, Tvalue>her bir değerin benzersiz anahtarıyla temsil edildiği yerin listesidir . Diyelim ki en sevdiğiniz yiyeceklerin bir listesi var. Her bir değer (yemek adı) benzersiz anahtarı ile temsil edilir (bir konum = bu yiyeceği ne kadar sevdiğiniz).

Örnek kod:

Dictionary<int, string> myDietFavorites = new Dictionary<int, string>()
{
    { 1, "Burger"},
    { 2, "Fries"},
    { 3, "Donuts"}
};

Diyelim ki sağlıklı kalmak istiyorsunuz, fikrinizi değiştirdiniz ve en sevdiğiniz "Burger" ı salata ile değiştirmek istiyorsunuz. Listeniz hala favorilerinizin bir listesidir, listenin doğasını değiştirmeyeceksiniz. Favoriniz listede bir numara olarak kalacak, sadece değeri değişecek. Bunu aradığın zamandır:

/*your key stays 1, you only replace the value assigned to this key
  you alter existing record in your dictionary*/
myDietFavorites[1] = "Salad";

Ancak programcı olduğunuzu unutmayın ve bundan sonra cümleleri ile bitirirsiniz; emojiyi kullanmayı reddediyorsunuz çünkü derleme hatası veriyorlar ve tüm sık kullanılanlar listesi 0 dizin tabanlıdır.

Diyetiniz de değişti! Yani listenizi yeniden değiştiriyorsunuz:

/*you don't want to replace Salad, you want to add this new fancy 0
  position to your list. It wasn't there before so you can either define it*/
myDietFavorites[0] = "Pizza";

/*or Add it*/
myDietFavorites.Add(0, "Pizza");

Tanımlamanın iki olasılığı vardır, ya daha önce var olmayan bir şeye yeni bir tanım vermek ya da zaten var olan tanımı değiştirmek istersiniz.

Ekle yöntemi bir kayıt eklemenize izin verir, ancak yalnızca tek bir koşulla: bu tanım için anahtar sözlüğünüzde olmayabilir.

Şimdi kaputun altına bakacağız. Bir sözlük oluştururken derleyiciniz kova için bir rezervasyon yapar (kayıtlarınızı saklamak için bellekte boşluklar). Paket, anahtarları sizin tanımladığınız şekilde saklamaz. Her bir anahtara (Microsoft tarafından tanımlanmıştır) gitmeden önce hashing uygulanır ve değer kısmının değişmeden kaldığını belirtmeye değer.

Örneğimi basitleştirmek için CRC32 karma algoritmasını kullanacağım. Tanımlarken:

myDietFavorites[0] = "Pizza";

Kovaya giden şey db2dc565 "Pizza" (basitleştirilmiş).

Değerini şununla değiştirdiğinizde:

myDietFavorites[0] = "Spaghetti";

Yine db2dc565 olan 0'ınıza hash uyguladınız ve orada olup olmadığını bulmak için kovanızda bu değeri ararsınız . Oradaysa, tuşa atanan değeri yeniden yazmanız yeterlidir. Orada değilse, değerinizi kovaya koyacaksınız.

Sözlüğünüzden Ekle işlevini aradığınızda, örneğin:

myDietFavorite.Add(0, "Chocolate");

Değerini gruptakilerle karşılaştırmak için 0 değerinize hashing uygulayabilirsiniz. Sadece orada değilse kovaya koyabilirsiniz .

Özellikle dize veya karakter tipi anahtar sözlükleriyle çalışıyorsanız, nasıl çalıştığını bilmek çok önemlidir. Karma işlemden geçmesi nedeniyle büyük / küçük harfe duyarlıdır. Örneğin "isim"! = "İsim". Bunu tasvir etmek için CRC32'imizi kullanalım.

"İsim" için değer: e04112b1 "Ad" için değer: 1107fb5b


Bu iki satırın anlaşılması için yeterli ....... Tanımlamada iki olasılık vardır, ya önceden var olmayan bir şey için yeni bir tanım vermek ya da zaten var olan tanımı değiştirmek istersiniz. Ekle yöntemi bir kayıt eklemenize izin verir, ancak yalnızca tek bir koşulla: bu tanım için anahtar sözlüğünüzde olmayabilir.
Niraj Trivedi

4

Evet, fark budur, anahtar zaten varsa, Add yöntemi bir özel durum oluşturur.

Add yöntemini kullanmanın nedeni tam olarak budur. Sözlüğün zaten anahtarı içermemesi gerekiyorsa, sorunun farkına varmanız için genellikle istisna olmasını istersiniz.


0

Performanstaki olası benzerliklerden daha fazlası göz önüne alındığında, kullandığınız kod parçası için daha doğru ve okunabilir olan her şeyi kullanın.

Bir eklemeyi tanımlayan bir işlem hissediyorum, anahtarın varlığı halihazırda gerçekten nadir görülen bir istisna, en iyi ekleme ile temsil edilir. Anlamsal olarak daha mantıklı.

Daha dict[key] = valueiyi bir ikameyi temsil eder. Bu kodu görürsem, anahtarın zaten sözlükte olmasını yarı yarıya bekliyorum.


Önce anahtarın var olup olmadığını kontrol etmemekle küçük bir performans kazancı olduğunu varsayıyorum. dic[key] = valueAnahtarın zaten mevcut olmasını beklemiyorum , ama sanırım bu tartışmalı;)
Sune Rievers

2
+ Bence anahtarın zaten temsil edilip edilmediğini kontrol etmenin bir yolu olarak atma asla kullanılmamalıdır. eğer (! strings.ContainsKey ("foo")) strings.Add ("foo", "bar");
hhravn

0

Biri bir değer atarken, diğeri Sözlüğe yeni bir Anahtar ve Değer ekliyor.


0

Değeri Sözlüğe eklemek için

 Dictionary<string, string> dDS1 = new Dictionary<string, string>();//Declaration
 dDS1.Add("VEqpt", "aaaa");//adding key and value into the dictionary
 string Count = dDS1["VEqpt"];//assigning the value of dictionary key to Count variable
 dDS1["VEqpt"] = Count + "bbbb";//assigning the value to key
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.