私はPythonのドキュメントで例を読みましたが、それでもこの方法が何を意味するのか理解できません。誰かが手伝ってくれる?これがpythonドキュメントからの2つの例です。
>>> from collections import defaultdict
>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
... d[k] += 1
...
>>> d.items()
[('i', 4), ('p', 2), ('s', 4), ('m', 1)]
そして
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
パラメータint
とlist
は何のためのものですか?
通常、現在辞書にないキーを持つ項目を取得しようとすると、Python辞書はKeyError
をスローします。対照的にdefaultdict
は単にあなたがアクセスしようとするどんなアイテムでも作成するでしょう(もちろんそれらがまだ存在しないという条件で)。そのような「デフォルト」項目を作成するには、コンストラクタに渡す関数オブジェクトを呼び出します(より正確には、それは関数オブジェクトと型オブジェクトを含む任意の「呼び出し可能」オブジェクトです)。最初の例では、デフォルトの項目はint()
を使って作成され、整数オブジェクト0
が返されます。 2番目の例では、デフォルトの項目はlist()
を使用して作成され、これは新しい空のリストオブジェクトを返します。
defaultdict
は、辞書にキーが見つからなかった場合、KeyError
がスローされる代わりに新しいエントリが作成されることを意味します。この新しいエントリのタイプは、defaultdictの引数によって与えられます。
例えば:
somedict = {}
print(somedict[3]) # KeyError
someddict = defaultdict(int)
print(someddict[3]) # print int(), thus 0
「標準辞書には、値を取得し、値が存在しない場合にデフォルトを設定するためのメソッドsetdefault()が含まれています。対照的に、defaultdict
では、コンテナの初期化時に呼び出し側がデフォルトを返します。
例によるPython標準ライブラリのDoug Hellmannで定義されているとおり
>>> from collections import defaultdict
渡してそれを初期化する
呼び出し可能 最初の引数として/ /(必須)
>>> d_int = defaultdict(int)
>>> d_list = defaultdict(list)
>>> def foo():
... return 'default value'
...
>>> d_foo = defaultdict(foo)
>>> d_int
defaultdict(<type 'int'>, {})
>>> d_list
defaultdict(<type 'list'>, {})
>>> d_foo
defaultdict(<function foo at 0x7f34a0a69578>, {})
** kwargs 2番目の引数として/(オプション)
>>> d_int = defaultdict(int, a=10, b=12, c=13)
>>> d_int
defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12})
または
>>> kwargs = {'a':10,'b':12,'c':13}
>>> d_int = defaultdict(int, **kwargs)
>>> d_int
defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12})
標準的な辞書の子クラスであるように、それはすべて同じ機能を実行することができます。
しかし、未知のキーを渡した場合、エラーではなくデフォルト値が返されます。例:
>>> d_int['a']
10
>>> d_int['d']
0
>>> d_int
defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12, 'd': 0})
デフォルト値を変更したい場合はdefault_factoryを上書きしてください。
>>> d_int.default_factory = lambda: 1
>>> d_int['e']
1
>>> d_int
defaultdict(<function <lambda> at 0x7f34a0a91578>, {'a': 10, 'c': 13, 'b': 12, 'e': 1, 'd': 0})
または
>>> def foo():
... return 2
>>> d_int.default_factory = foo
>>> d_int['f']
2
>>> d_int
defaultdict(<function foo at 0x7f34a0a0a140>, {'a': 10, 'c': 13, 'b': 12, 'e': 1, 'd': 0, 'f': 2})
例1
Intがdefault_factoryとして渡されたので、未知のキーはデフォルトで0を返します。
文字列がループに渡されると、dのアルファベットの数が増えます。
>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> d.default_factory
<type 'int'>
>>> for k in s:
... d[k] += 1
>>> d.items()
[('i', 4), ('p', 2), ('s', 4), ('m', 1)]
>>> d
defaultdict(<type 'int'>, {'i': 4, 'p': 2, 's': 4, 'm': 1})
例2
リストがdefault_factoryとして渡されたので、未知の(存在しない)キーはデフォルトで[](すなわちlist)を返します。
タプルのリストがループで渡されると、d [color]に値が追加されます。
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> d.default_factory
<type 'list'>
>>> for k, v in s:
... d[k].append(v)
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
>>> d
defaultdict(<type 'list'>, {'blue': [2, 4], 'red': [1], 'yellow': [1, 3]})
ここでdefaultdictsの素晴らしい説明があります: http://ludovf.net/blog/python-collections-defaultdict/
基本的に、パラメータ int および list は、渡す関数です。 Pythonは引数として関数名を受け入れます。 int はデフォルトで0を返し、 list は括弧付きで呼び出されると空のリストを返します。
通常の辞書では、あなたの例でd[a]
を呼び出そうとすると、キーm、s、i、pのみが存在し、キーaは初期化されていないので、エラー(KeyError)が出ます。しかしdefaultdictでは、それは引数として関数名を取り、初期化されていないキーを使用しようとすると、それは単にあなたが渡した関数を呼び出し、その戻り値を新しいキーの値として割り当てます。
辞書は、後で名前(キー)で検索できるようにデータを保存するのに便利な方法です。キーは一意で不変のオブジェクトでなければならず、通常は文字列です。辞書の値は何でも構いません。多くのアプリケーションでは、値は整数や文字列などの単純型です。
辞書内の値がコレクション(リスト、辞書など)である場合は、さらに興味深いものになります。この場合、値(空のリストまたは辞書)は、特定のキーが初めて使用されるときに初期化する必要があります。これは手動で行うのは比較的簡単ですが、defaultdictタイプはこれらの種類の操作を自動化して単純化します。 defaultdictは通常の辞書とまったく同じように機能しますが、引数を取らず、存在しないキーのデフォルト値を提供する関数( "default factory")で初期化されます。
Defaultdictは決してKeyErrorを送出しません。存在しないキーは、デフォルトファクトリによって返される値を取得します。
from collections import defaultdict
ice_cream = defaultdict(lambda: 'Vanilla')
ice_cream = defaultdict(lambda: 'Vanilla')
ice_cream['Sarah'] = 'Chunky Monkey'
ice_cream['Abdul'] = 'Butter Pecan'
print(ice_cream['Sarah'])
>>>Chunky Monkey
print(ice_cream['Joe'])
>>>Vanilla
from collections import defaultdict
# Time complexity O(n^2)
def delete_nth_naive(array, n):
ans = []
for num in array:
if ans.count(num) < n:
ans.append(num)
return ans
# Time Complexity O(n), using hash tables.
def delete_nth(array,n):
result = []
counts = defaultdict(int)
for i in array:
if counts[i] < n:
result.append(i)
counts[i] += 1
return result
x = [1,2,3,1,2,1,2,3]
print(delete_nth(x, n=2))
print(delete_nth_naive(x, n=2))
結論として、辞書が必要で、各要素の値がデフォルト値で始まっている場合は、defaultdictを使用してください。
私自身の2¢:defaultdictをサブクラス化することもできます。
class MyDict(defaultdict):
def __missing__(self, key):
value = [None, None]
self[key] = value
return value
これは非常に複雑な場合に便利です。
問題は「どのように機能するのか」ということなので、読者の中にはもっと多くのことを知りたいと思う人がいるかもしれません。具体的には、問題のメソッドは__missing__(key)
メソッドです。 https://docs.python.org/2/library/collections.html#defaultdict-objects を参照してください。
より具体的には、この答えは実用的な方法で__missing__(key)
を活用する方法を示しています: https://stackoverflow.com/a/17956989/1593924
'callable'が何を意味するのかを明確にするために、これは対話的なセッションです(2.7.6からですがv3でも動作するはずです):
>>> x = int
>>> x
<type 'int'>
>>> y = int(5)
>>> y
5
>>> z = x(5)
>>> z
5
>>> from collections import defaultdict
>>> dd = defaultdict(int)
>>> dd
defaultdict(<type 'int'>, {})
>>> dd = defaultdict(x)
>>> dd
defaultdict(<type 'int'>, {})
>>> dd['a']
0
>>> dd
defaultdict(<type 'int'>, {'a': 0})
これがdefaultdictの最も一般的な使用方法です(x変数の無意味な使用方法を除く)。明示的なデフォルト値として0でも同じことができますが、単純な値ではできません。
>>> dd2 = defaultdict(0)
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
dd2 = defaultdict(0)
TypeError: first argument must be callable
代わりに、次のコードは単純な関数を渡すので機能します(引数を取らず常に0を返す名前のない関数をその場で作成します)。
>>> dd2 = defaultdict(lambda: 0)
>>> dd2
defaultdict(<function <lambda> at 0x02C4C130>, {})
>>> dd2['a']
0
>>> dd2
defaultdict(<function <lambda> at 0x02C4C130>, {'a': 0})
>>>
そしてデフォルト値を変えて:
>>> dd3 = defaultdict(lambda: 1)
>>> dd3
defaultdict(<function <lambda> at 0x02C4C170>, {})
>>> dd3['a']
1
>>> dd3
defaultdict(<function <lambda> at 0x02C4C170>, {'a': 1})
>>>
defaultdict
がなければ、目に見えないキーに新しい値を代入することは可能ですが、それを変更することはできません。例えば:
import collections
d = collections.defaultdict(int)
for i in range(10):
d[i] += i
print(d)
# Output: defaultdict(<class 'int'>, {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9})
import collections
d = {}
for i in range(10):
d[i] += i
print(d)
# Output: Traceback (most recent call last): File "python", line 4, in <module> KeyError: 0
Switch case文の代わりに使うのが一番だと思います。次のようにswitch case文があるとします。
option = 1
switch(option) {
case 1: print '1st option'
case 2: print '2nd option'
case 3: print '3rd option'
default: return 'No such option'
}
Pythonにはswitch
case文はありません。 defaultdict
を使っても同じことができます。
from collections import defaultdict
def default_value(): return "Default Value"
dd = defaultdict(default_value)
dd[1] = '1st option'
dd[2] = '2nd option'
dd[3] = '3rd option'
print(dd[4])
print(dd[5])
print(dd[3])
それは印刷されます:
Default Value
Default Value
3rd option
上記のスニペットでは、dd
は4または5のキーを持っていないので、ヘルパー関数で設定したデフォルト値を表示します。これは、キーが存在しない場合にKeyError
がスローされる生の辞書よりもかなり優れています。このことから、defaultdict
はより複雑なif-Elif-elif-else
ブロックを避けることができるswitch case文のようなものであることは明らかです。
このサイト から私に多くの印象を与えたもう一つの良い例は:
>>> from collections import defaultdict
>>> food_list = 'spam spam spam spam spam spam eggs spam'.split()
>>> food_count = defaultdict(int) # default value of int is 0
>>> for food in food_list:
... food_count[food] += 1 # increment element's value by 1
...
defaultdict(<type 'int'>, {'eggs': 1, 'spam': 7})
>>>
eggs
とspam
以外の項目にアクセスしようとすると、カウントは0になります。
DefaultdictツールはPythonのcollectionsクラスのコンテナです。通常の辞書(dict)コンテナに似ていますが、違いが1つあります。値フィールドのデータ型は初期化時に指定されます。
例えば:
from collections import defaultdict
d = defaultdict(list)
d['python'].append("awesome")
d['something-else'].append("not relevant")
d['python'].append("language")
for i in d.items():
print i
これは印刷します:
('python', ['awesome', 'language'])
('something-else', ['not relevant'])
まあ、defaultdictは次のような場合にもキーエラーを引き起こす可能性があります。
from collections import defaultdict
d = defaultdict()
print(d[3]) #raises keyerror
Defaultdict(int)のようにdefaultdictに引数を与えるのを忘れないでください。
標準辞書には、値を取得し、値が存在しない場合にデフォルトを設定するためのメソッドsetdefault()が含まれています。対照的に、defaultdictは、コンテナが初期化されたときに呼び出し側にデフォルトのデフォルトを指定させます。
import collections
def default_factory():
return 'default value'
d = collections.defaultdict(default_factory, foo='bar')
print 'd:', d
print 'foo =>', d['foo']
print 'bar =>', d['bar']
すべてのキーに同じデフォルトが設定されているのが適切である限り、これはうまく機能します。デフォルトが、リスト、セット、さらにはintなど、値の集約または累積に使用される型である場合に特に役立ちます。標準ライブラリのドキュメントには、このようにdefaultdictを使用するいくつかの例が含まれています。
$ python collections_defaultdict.py
d: defaultdict(<function default_factory at 0x100468c80>, {'foo': 'bar'})
foo => bar
bar => default value
要するに:
defaultdict(int)
- 引数intは、値がint型になることを示します。
defaultdict(list)
- 引数listは値がリスト型になることを示します。