の値で呼び出し.setdefault()
ましたv
:
newlist.setdefault(v,[])
とv
がすでに定義されていて、 に設定されている必要があります'go'
。このコードを新しいインタープリターで実行するか、del v
最初に実行すると、Python はNameError
代わりに例外を発生させます。
>>> newlist = {}
>>> newlist.setdefault(v,[]).append((v,k) for k,v in dicnew.items() if v==value)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'v' is not defined
>>> v = 'go'
>>> newlist.setdefault(v, [])
[]
>>> newlist
{'go': []}
このsetdefault()
部分は、.append()
メソッドが実行される前に実行されます。メソッドv
内のジェネレーター式で使用される名前は、呼び出しで使用される名前とは関係ありません。.append()
v
.setdefault()
Python 2.7 以前では、親スコープに「リーク」する内包変数を一覧表示します。
>>> [foo for foo in range(3)]
[0, 1, 2]
>>> foo
2
そのため、v
は前のループで設定され、最後に割り当てられた値は'go'
です。
各値のキーのリストを収集して辞書を「反転」したい場合は、次を使用します。
from collections import defaultdict
keys_for_value = defaultdict(list)
for key, value in original_dict.iteritems():
keys_for_value[value].append(key)
ワンライナーを主張する必要がある場合は、次を使用itertools.groupby
して並べ替えます。
from itertools import groupby
from operator import itemgetter
v = itemgetter(1)
keys_for_value = {value: [k for k, v in items] for value, items in groupby(sorted(original_dict.iteritems(), key=v, key=v)}
ソートされた結果 (それ自体 O(n)) をループする前に、最初に辞書項目をソートする必要があるため (コスト O(n log n))、これは遅くなります。つまり、合計 O(n) + O(n log n)) を使用する単純な O(n) の複雑さdefaultdict
とfor
ループとは対照的です。