How does collections.defaultdict work?
我已经阅读了python文档中的示例,但仍然无法理解这个方法的含义。有人能帮忙吗?下面是来自python文档的两个示例
1 2 3 4 5 6 7 8 9 | >>> 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)] |
和
1 2 3 4 5 6 7 | >>> 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])] |
参数
通常,如果您试图获取一个带有当前不在字典中的键的项,那么python字典会抛出一个
例如:
1 2 3 4 5 | somedict = {} print(somedict[3]) # KeyError someddict = defaultdict(int) print(someddict[3]) # print int(), thus 0 |
拖欠债务
"标准字典包括方法setdefault(),用于检索值并在值不存在时建立默认值。相比之下,
由Doug Hellmann在Python标准库中通过示例定义
如何使用defaultdict导入默认dict1 | >>> from collections import defaultdict |
初始化默认dict
通过传递初始化它
callable as its first argument(mandatory)
1 2 3 4 5 6 7 8 9 10 11 12 | >>> 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 as its second argument(optional)
1 2 3 | >>> d_int = defaultdict(int, a=10, b=12, c=13) >>> d_int defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12}) |
或
1 2 3 4 | >>> kwargs = {'a':10,'b':12,'c':13} >>> d_int = defaultdict(int, **kwargs) >>> d_int defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12}) |
它是怎么工作的
作为标准字典的子类,它可以执行所有相同的功能。
但是,如果传递一个未知的键,它将返回默认值而不是错误。对于EX:
1 2 3 4 5 6 | >>> d_int['a'] 10 >>> d_int['d'] 0 >>> d_int defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12, 'd': 0}) |
如果要更改默认值,请覆盖默认工厂:
1 2 3 4 5 | >>> 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}) |
或
1 2 3 4 5 6 7 | >>> 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已作为默认的u工厂传递,任何未知的键在默认情况下都将返回0。
现在,当字符串在循环中传递时,它将增加d中这些字母的计数。
1 2 3 4 5 6 7 8 9 10 | >>> 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
由于列表已作为默认工厂传递,因此默认情况下,任何未知(不存在)键都将返回[](即列表)。
现在,当在循环中传递元组列表时,它将在d[颜色]中附加值。
1 2 3 4 5 6 7 8 9 10 | >>> 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返回空列表。
在普通字典中,如果在您的示例中我尝试调用
字典是一种方便的存储数据的方法,以便以后按名称(键)检索。键必须是唯一的、不可变的对象,并且通常是字符串。字典中的值可以是任何值。对于许多应用程序,值是简单的类型,如整数和字符串。
当字典中的值是集合(列表、dict等)时,会变得更有趣。在这种情况下,必须在第一次使用给定键时初始化值(空列表或dict)。虽然手工操作相对容易,但默认dict类型自动执行并简化了这些操作。默认dict的工作方式与普通dict完全相同,但它是用一个不带参数并为不存在的键提供默认值的函数("默认工厂")初始化的。
默认dict将永远不会引发keyError。任何不存在的键都将获取默认工厂返回的值。
1 2 3 4 5 6 7 8 9 10 | 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 |
下面是另一个例子,如何使用defaultdict?如何降低复杂性?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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子类:
1 2 3 4 5 | class MyDict(defaultdict): def __missing__(self, key): value = [None, None] self[key] = value return value |
对于非常复杂的情况,这可能很有用。
由于问题是关于"它是如何工作的",一些读者可能希望看到更多的螺母和螺栓。具体来说,所讨论的方法是
更具体地说,这个答案说明了如何以实际的方式使用
为了阐明"可调用"的含义,这里有一个交互式会话(从2.7.6开始,但也应该在v3中使用):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | >>> 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执行与显式默认值相同的操作,但不能使用简单值:
1 2 3 4 5 6 | >>> 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的无名称函数):
1 2 3 4 5 6 7 8 | >>> dd2 = defaultdict(lambda: 0) >>> dd2 defaultdict(<function <lambda> at 0x02C4C130>, {}) >>> dd2['a'] 0 >>> dd2 defaultdict(<function <lambda> at 0x02C4C130>, {'a': 0}) >>> |
使用不同的默认值:
1 2 3 4 5 6 7 8 | >>> dd3 = defaultdict(lambda: 1) >>> dd3 defaultdict(<function <lambda> at 0x02C4C170>, {}) >>> dd3['a'] 1 >>> dd3 defaultdict(<function <lambda> at 0x02C4C170>, {'a': 1}) >>> |
如果没有
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
在以下情况下,defaultdict还可以引发keyerror:
1 2 3 | from collections import defaultdict d = defaultdict() print(d[3]) #raises keyerror |
总是记得像defaultdict(int)那样为defaultdict提供参数。
defaultdict工具是python集合类中的一个容器。它类似于通常的字典(dict)容器,但有一个区别:值字段的数据类型是在初始化时指定的。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
印刷品:
1 2 | ('python', ['awesome', 'language']) ('something-else', ['not relevant']) |
我认为它最好用来代替switch case语句。假设我们有一个switch case语句,如下所示:
1 2 3 4 5 6 7 8 | 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中没有可用的
1 2 3 4 5 6 7 8 9 10 11 12 | 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]) |
它打印:
1 2 3 | Default Value Default Value 3rd option |
在上面的代码段中,
另一个让我印象深刻的例子是:
1 2 3 4 5 6 7 8 | >>> 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}) >>> |
如果我们尝试访问除
总之:
标准字典包含方法setdefault(),用于检索值并在值不存在时建立默认值。相反,defaultdict允许调用者在初始化容器时预先指定默认值。
1 2 3 4 5 6 7 8 9 | 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的示例。
1 2 3 4 5 | $ python collections_defaultdict.py d: defaultdict(<function default_factory at 0x100468c80>, {'foo': 'bar'}) foo => bar bar => default value |
文件和解释几乎是不言自明的:
http://docs.python.org/library/collections.html collections.defaultdict
作为参数传递的类型函数(int/str等)用于初始化字典中不存在该键的任何给定键的默认值。