Belirli bir anahtarın sözlükte zaten mevcut olup olmadığını kontrol edin ve artırın


295

Bir sözlük verildiğinde, sözlüğün belirli bir anahtarının zaten Yok olmayan bir değere ayarlanmış olup olmadığını nasıl öğrenebilirim?

Yani, bunu yapmak istiyorum:

my_dict = {}

if (my_dict[key] != None):
  my_dict[key] = 1
else:
  my_dict[key] += 1

Yani, zaten bir tane varsa değeri arttırmak veya aksi takdirde 1 olarak ayarlamak istiyorum.


11
Küçük kod nitpick: Zaten orada bir şey varsa kod my_dict [key] değerini 1 olarak ayarlar ve yoksa artırır. Bence == istiyorsun, değil! =.
QuantumFool

Yanıtlar:


331

Aradığınız collections.defaultdict(Python 2.5+ için mevcut). Bu

from collections import defaultdict

my_dict = defaultdict(int)
my_dict[key] += 1

ne istersen yapacak.

Düzenli Python için dicthiçbir değer verilen bir anahtar için varsa ler, sen olacak değil almak Nonedicti erişirken - Bir KeyErrorarttırılacaktır. Yani normal bir dictkod kullanmak istiyorsanız, kodunuz yerine

if key in my_dict:
    my_dict[key] += 1
else:
    my_dict[key] = 1

8
Örneğine göre, "defaultdict (lambda: 0)" ayarlamak ve "if" yan tümcesini atlamak yeterli olmalıdır.
Deestan

Bu çalışır, ancak anahtarları ve değerleri karıştırır (okumayı biraz garip hale getirir). 'some_value' 'some_key' olmalıdır
mikemaccana

@ nailer: düzeltildi, teşekkürler. Başlangıçta 'some_value' kullanmıştım, çünkü bu sorudaki değişken adı, ama şimdi daha net olduğunu kabul ediyorum.
dF.

20
... ya da normal dicts için yapabilirsiniz my_dict[key] = my_dict.get(key, 0) + 1.
minmaxavg

Bunu iç içe sözlüklere nasıl genişletebilirim? dikte [anahtar1] [anahtar2] + = 1?
Pablo Ruiz Ruiz

301

Bunu bir kod satırında yapmayı tercih ederim.

my_dict = {}

my_dict [some_key] = my_dict.get (bazı_anahtar, 0) + 1

Sözlüklerin get fonksiyonu iki parametre alır - istediğiniz anahtar ve yoksa varsayılan değer. Ben sadece anahtar bu kod satırında değil, her yerde değil durumda işlemek istediğiniz için varsayılan olarak bu yöntemi tercih ederim.


1
@AndrewWilkinson kötülerim. Cevabımı olması gerektiği kadar iyi okumadım.
masaers

59

Şahsen kullanmayı seviyorum setdefault()

my_dict = {}

my_dict.setdefault(some_key, 0)
my_dict[some_key] += 1

setdefaultharika. Önceden ayarlanmışsa, değeri değiştirmez some_key. Örneğin d={1:2}; d.setdefault(1, 0), değerini bozmaz d[1].
wsaleem

49

Bunun için key in dictdeyime ihtiyacınız var.

if key in my_dict and not (my_dict[key] is None):
  # do something
else:
  # do something else

Bununla birlikte, muhtemelen defaultdict(dF'nin önerdiği gibi) kullanmayı düşünmelisiniz .


1
En az 2.6 has_key () 'in d. Sanırım 2.5'te de bu şekilde oldu.
David Locke

Unutmayın ki my_dict[key] is not None, daha net (en azından IMHO)
yazabilir

@brandizzi - katılıyorum,if key in my_dict and my_dict[key]:
Rob Grant

18

" Bu dikendeki belirli bir dizinin zaten Yok olmayan bir değere ayarlanmış olup olmadığını nasıl öğrenebilirim? " Sorusunu yanıtlamak için şunu tercih ederim:

try:
  nonNone = my_dict[key] is not None
except KeyError:
  nonNone = False

Bu halihazırda çağrılmış olan EAFP konseptine uygundur (affetme istemek, ardından izin almak daha kolaydır). Ayrıca, arama pahalıysa key in my_dict and my_dict[key] is not None, ilginç olan şeyde olduğu gibi sözlükte yinelenen anahtar aramasını da önler .

Gerçekte karşılaştığınız sorun için, örneğin, varsa int değerini artırmak veya başka bir varsayılan değere ayarlamak için,

my_dict[key] = my_dict.get(key, default) + 1

Andrew Wilkinson'ın cevabında olduğu gibi.

Sözlüğünüzde değiştirilebilir nesneler saklıyorsanız üçüncü bir çözüm vardır. Bunun yaygın bir örneği , anahtarlarınız için bir öğe listesi sakladığınız bir multimap'tır . Bu durumda şunları kullanabilirsiniz:

my_dict.setdefault(key, []).append(item)

Sözlükte anahtar için bir değer yoksa, setdefault yöntemi bunu setdefault öğesinin ikinci parametresine ayarlar. Tıpkı standart bir my_dict [key] gibi davranarak anahtarın değerini döndürür (yeni ayarlanan değer olabilir).


gerçekten Pythonic (benim gibi bir yabancıya) görünen herhangi bir soru en az 3 geçerli cevap var :)
davka

@davka: Üç kullanım durumu neredeyse aynı, ancak farklı: a) sözlükte Yok olmayan bir öğe olup olmadığını bulma b) sözlükten bir değer alma veya değer yoksa varsayılanı kullanma c) sözlükten bir değer alın ve değer henüz yoksa varsayılanı saklayın.
nd.

Biliyorum :) Bu bir eleştiri değil, ben sadece bu gerçeği eğlendiriyorum
davka

@ Ryeguy'un cevabına yaptığı bir yorumda Stuart Woodward, "Dilde İstisna işleme konusundaki genel gider, her zaman öğenin sözlükte olup olmadığını belirleyen karma tablo aramasından daha büyük bir büyüklük sırasıdır", "Bu Ayrıca sözlükte yinelenen anahtar aramasını önler ... eğer arama pahalıysa "- istisna işlemenin çift anahtar aramasından daha hızlı veya daha yavaş olduğu herhangi bir ölçüm var mı?
Michael Firth

1
@MichaelFirth Python'un istisna yükü için lanetli bir arama yaptım: stackoverflow.com/questions/2522005/… daha yavaş, ama çok fazla değil. Bir istisna atma kavramının farklı dillerde çok farklı ele alındığını ve artıları ve eksileri genelleştiremeyeceğinizi unutmayın. Bu nedenle, "İstisnalar 10x ek yüke sahip" Java için doğru olsa da, Python (veya Swift veya diğerleri) için doğru değildir.
nd.

13

Cgoldberg ile anlaştı. Nasıl yaparım:

try:
    dict[key] += 1
except KeyError:
    dict[key] = 1

Bu yüzden ya yukarıdaki gibi yapın ya da başkalarının önerdiği gibi varsayılan bir dikte kullanın. İf ifadelerini kullanmayın. Bu Pythonic değil.


8
İfadeler Pythonic değilse nasıl olur?
Adam Parkin

2
Bu Python EAFP en iyi yolu olmadığı bir durum olduğunu düşünüyorum. Yukarıdaki örnekte yinelenen kod var; Bir gün biz neyi istiyorsanız +=2veya -=1? Her iki satırı da değiştirmeyi unutmamalısınız. Şimdi önemsiz bir şey gibi görünebilir, ancak bunlar sizi ısırmaya geri dönebilecek aptal küçük 'önemsiz' böceklerdir.
Cam Jackson

3
Bu güzel görünüyor ve iyi çalışıyor, ancak genellikle böyle yapmaktan kaçınırım çünkü dilde İstisna işlemedeki ek yükün her zaman öğenin sözlükte olup olmadığını belirleyen karma tablo aramasından daha büyük bir büyüklük sırası olduğunu düşündüm.
Stuart Woodward

11

Birçok cevaptan görebileceğiniz gibi, birkaç çözüm var. Bir LBYL örneğinden (sıçramadan önce bak) henüz bahsedilmedi, has_key () yöntemi:

my_dict = {}

def add (key):
    if my_dict.has_key(key):
        my_dict[key] += 1
    else:
        my_dict[key] = 1

if __name__ == '__main__':
    add("foo")
    add("bar")
    add("foo")
    print my_dict

6
has_key () 'in' operatöründen daha yavaştır ve daha az okunabilir.
Abgan

9
... ve Python 2.6'da kullanımdan kaldırıldı ve Python 3'te kaldırıldı.
Tim Pietzcker

7

Değerinizi artırmaya çalışmadan önce koşulları kontrol ettiğiniz için bunu yapmaya çalıştığınız yol LBYL (sıçramadan önce bakın) olarak adlandırılır.

Diğer yaklaşıma EAFP denir (affetmeyi istemekten sonra izin almak daha kolaydır). Bu durumda, işlemi denemeniz yeterlidir (değeri artırın). Başarısız olursa, istisnayı yakalar ve değeri 1 olarak ayarlarsınız. Bu, bunu yapmanın biraz daha Pythonic yoludur (IMO).

http://mail.python.org/pipermail/python-list/2003-May/205182.html


5

Biraz geç ama bu işe yarayacak.

my_dict = {}
my_dict[key] = my_dict[key] + 1 if key in my_dict else 1

Vay, bir Java programcısı olarak, bu oldukça çılgın görünümlü bir yapı. Tuhaf bir şekilde düzenlenmiş üçlü bir operatör gibi mi görünüyor?
forresthopkinsa

5

Bu doğrudan soruyu cevaplamıyor, ama bana göre, koleksiyonların işlevselliğini isteyebileceğiniz gibi görünüyor .

from collections import Counter

to_count = ["foo", "foo", "bar", "baz", "foo", "bar"]

count = Counter(to_count)

print(count)

print("acts just like the desired dictionary:")
print("bar occurs {} times".format(count["bar"]))

print("any item that does not occur in the list is set to 0:")
print("dog occurs {} times".format(count["dog"]))

print("can iterate over items from most frequent to least:")
for item, times in count.most_common():
    print("{} occurs {} times".format(item, times))

Bu çıktı ile sonuçlanır

Counter({'foo': 3, 'bar': 2, 'baz': 1})
acts just like the desired dictionary:
bar occurs 2 times
any item that does not occur in the list is set to 0:
dog occurs 0 times
can iterate over items from most frequent to least:
foo occurs 3 times
bar occurs 2 times
baz occurs 1 times

Sayaç defaultdict(int)bazı ekstra işlevlerde olduğu gibi çalışır, bu nedenle yalnızca tamsayılarla uğraşırken mükemmel çalışır, ancak ilgili davranışlardan hiçbirini göstermezsiniz.
Tadhg McDonald-Jensen

4

İşte bu sorunu çözmek için son zamanlarda bulduğum bir astar. Setdefault sözlük yöntemine dayanmaktadır :

my_dict = {}
my_dict[key] = my_dict.setdefault(key, 0) + 1

0

Onu arıyordum, web'de bulamadım sonra şansımı Try / Error ile denedim ve buldum

my_dict = {}

if my_dict.__contains__(some_key):
  my_dict[some_key] += 1
else:
  my_dict[some_key] = 1

1
Sen kullanarak olmamalıdır __contains__üretim kodunda. Btw. __contains__kullanmakla aynıdır is.
user1767754

1
my_dict.__contains__(some_key)ile eşdeğerdir some_key in my_dict, inoperatör için aşırı yük değilis
Tadhg McDonald-Jensen
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.