指定されたキーが辞書にすでに存在するかどうかを確認し、それをインクリメントします


295

ディクショナリが与えられた場合、そのディクショナリの特定のキーがすでにNon-None値に設定されているかどうかをどのように確認できますか?

つまり、私はこれをしたいです:

my_dict = {}

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

つまり、すでに値がある場合は値を増やし、それ以外の場合は1に設定します。


11
小さなコードnitpick:コードは、my_dict [key]に既に何かがある場合は1に設定し、ない場合はインクリメントします。==ではなく、==が欲しいと思います。
QuantumFool

回答:


331

あなたは探していますcollections.defaultdict(Python 2.5+で利用可能)。この

from collections import defaultdict

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

あなたがしたいことをします。

通常のPythonではdict、指定されたキーに値がないNone場合、dictにアクセスして取得されません-a KeyErrorが発生します。したがって、通常のを使用したい場合dictは、コードの代わりに

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

8
彼の例によれば、「defaultdict(lambda:0)」を設定して「if」句全体をスキップするだけで十分です。
Deestan 2009年

これは機能しますが、キーと値を混同します(読みづらくなります)。「some_value」は「some_key」である必要があります
mikemaccana

@nailer:修正、ありがとう。「some_value」は質問の変数名なので、最初は「some_value」を使用していましたが、今ではより明確になっていることに同意します。
dF。

20
...または通常dictのsの場合、実行できますmy_dict[key] = my_dict.get(key, 0) + 1
minmaxavg 2016年

これをネストされた辞書に拡張する方法は?dict [key1] [key2] + = 1?
Pablo Ruiz Ruiz

301

私はこれを1行のコードで行うことを好みます。

my_dict = {}

my_dict [some_key] = my_dict.get(some_key、0)+ 1

辞書にはgetという関数があり、2つのパラメーター(必要なキーと、存在しない場合のデフォルト値)を取ります。このメソッドはdefaultdictよりも優先されます。キーがこのコードの1行に存在しない場合にのみ処理する必要があるためです。


1
@AndrewWilkinson私の悪い。私のようにあなたの答えを十分に読みませんでした。
masaers 2018

59

個人的に使うのが好き setdefault()

my_dict = {}

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

setdefaultすごい。に値がすでに設定されてsome_keyいる場合、値は変更されません。たとえばd={1:2}; d.setdefault(1, 0)、の値を妨害しませんd[1]
wsaleem

49

key in dictそのためのイディオムが必要です。

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

ただし、おそらく使用を検討する必要がありますdefaultdict(dFが提案したとおり)。


1
少なくとも2.6では、has_key()が廃止され、dのキーが優先されます。2.5でもそうだったと思います。
デビッドロック

my_dict[key] is not Noneより明確な(少なくとも
IMHO

@brandizzi-同意しますif key in my_dict and my_dict[key]:
Rob Grant

18

その辞書の特定のインデックスがすでにNon-None値に設定されているかどうかを確認するにはどうすればよいですかという質問に答えるには、次のようにします

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

これは、すでに呼び出されているEAFPの概念に適合します(許しを求めてから許可を求める方が簡単です)。またkey in my_dict and my_dict[key] is not None、検索にコストがかかる場合に興味深いことになるように、辞書での重複キー検索を回避します。

あなたが提起した実際の問題、つまり、存在する場合はintをインクリメントするか、それ以外の場合はデフォルト値に設定するために、

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

アンドリュー・ウィルキンソンの答えのように。

変更可能なオブジェクトをディクショナリに格納する場合、3番目の解決策があります。この一般的な例は、キーの要素のリストを格納するmultimapです。その場合、以下を使用できます。

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

keyの値が辞書に存在しない場合、setdefaultメソッドはそれをsetdefaultの2番目のパラメーターに設定します。これは標準のmy_dict [key]と同じように動作し、キーの値(新しく設定された値の場合もあります)を返します。


(私のような部外者にとって)確かにPythonicに見えるのは、どの質問にも少なくとも3つの有効な回答があるということです:)
davka

@davka:まあ、3つのユースケースはほとんど同じですが異なります:a)辞書にNone以外の要素があるかどうかを調べますb)辞書から値を取得するか、値が存在しない場合はデフォルトを使用しますc)辞書から値を取得し、値がまだ存在しない場合はデフォルトを保存します。
nd。

私は知っています:)これは批評ではありません、私はこの事実にただ面白がっています
davka

@ryeguyの回答へのコメントで、スチュアートウッドワードは、「言語での例外処理のオーバーヘッドは、項目が辞書に存在するかどうかを決定するハッシュテーブル検索よりも常に1桁大きい」と示唆しています。ディクショナリでの重複キールックアップも回避します...ルックアップにコストがかかる場合」-二重キールックアップよりも例外処理が高速または低速である場所を測定できる人はいますか
マイケルファース

1
@MichaelFirth私は、Pythonの例外オーバーヘッドのためのぞんざいな検索をした:stackoverflow.com/questions/2522005/...それはたくさんによって遅くですが、ありません。例外スローするという高レベルの概念は言語によって処理方法が大きく異なり、賛否両論を一般化することはできないことに注意してください。したがって、「例外には10倍のオーバーヘッドがあります」はJavaでは正しいかもしれませんが、Python(またはSwiftなど)では正しくありません。
nd。

13

cgoldbergに同意しました。私のやり方は:

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

したがって、上記のようにするか、他の人が示唆しているようにデフォルトの辞書を使用します。ifステートメントは使用しないでください。それはPythonicではありません。


8
ifステートメントがPythonicでない場合はどうなりますか?
アダムパーキン

2
これは、PythonのEAFPが最善の方法ではない1つのケースだと思います。上記の例ではコードが重複しています。ある日、私たちが望む+=2場合は-=1どうなりますか?両方の行を変更することを忘れないでください。今では些細なことのように思えるかもしれませんが、それらは、あなたに噛み付くように戻ってくることができる、一種の愚かな小さな「小さな」バグです。
Cam Jackson

3
これは見栄えがよく、正常に動作しますが、言語での例外処理のオーバーヘッドは、項目が辞書に存在するかどうかを決定するハッシュテーブルルックアップよりも常に1桁大きいと思ったため、通常はこのようにすることは避けます。
スチュアートウッドワード

11

多くの答えからわかるように、いくつかの解決策があります。LBYLの1つのインスタンス(跳躍する前に見える)はまだ言及されていません、has_key()メソッド:

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'演算子よりも遅く、読みにくくなります。
アブガン、2009年

9
...そしてそれは、Python 2.6で非推奨とPython 3で削除されました
ティムPietzcker

7

値をインクリメントする前に条件をチェックしているため、これを実行しようとしている方法はLBYL(ジャンプする前に見る)と呼ばれます。

もう1つの方法はEAFPと呼ばれます(許しを求めてから許可を求める方が簡単です)。その場合は、操作を試すだけです(値を増やします)。失敗した場合は、例外をキャッチして値を1に設定します。これは、これを行うための少しPython的な方法です(IMO)。

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


5

少し遅れますが、これでうまくいくはずです。

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

うわー、Javaプログラマーとして、これはかなりクレイジーに見える構造です。奇妙な順序の三項演算子のように見えますか?
フォレストホプキンサ2017

5

これは直接質問に答えるものではありませんが、私には、collections.Counterの機能が必要なようです。

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

これは出力になります

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

Counterはdefaultdict(int)、いくつかの追加機能と同様に機能するため、整数のみを処理する場合に完全に機能しますが、関連する動作は表示されません。
Tadhg McDonald-Jensen 2017

4

これが、この問題を解決するために最近思いついたワンライナーです。これは、setdefault辞書メソッドに基づいています

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

0

私はそれを探していました、それをウェブ上で見つけられなかったそしてそれからトライ/エラーで私の運を試し、それを見つけました

my_dict = {}

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

1
運用__contains__コードでは使用しないでください。ところで。__contains__を使用するのと同じisです。
user1767754

1
my_dict.__contains__(some_key)はと同等でありsome_key in my_dictinオペレーターにとっては過負荷ではありませんis
Tadhg McDonald-Jensen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.