考虑以下代码:from collections import Counter
from cytoolz import merge_with
my_list = ["a", "b", "a", "a", "c", "d", "b"]
my_dict = {"a" : "blue", "b" : "green", "c" : "yellow", "d" : "red", "e" : "black"}
pair_dict = merge_with(tuple, my_dict, Counter(my_list))
我得到以下pair_dict:
^{pr2}$
在我的实际应用程序中,我需要pair_dict中的值是成对的,因此pair_dict["e"]应该是{}。在
如果我能有一个用defaultdict(int)良好行为扩展Counter的类,那将非常方便。在
这容易做吗?在
我天真地尝试了以下方法:class DefaultCounter(defaultdict, Counter):
pass
pair_dict = merge_with(tuple, my_dict, DefaultCounter(my_list))
但我得到TypeError: first argument must be callable or None。我想这是由于defaultdict需要一个工厂函数。在
所以我尝试了以下方法:pair_dict = merge_with(tuple, my_dict, DefaultCounter(int, my_list))
这将导致ValueError: dictionary update sequence element #0 has length 1; 2 is required。在
我也尝试了class DefaultCounter(Counter, defaultdict),但没有达到预期效果:pair_dict["e"]仍然是{}。在
也许在类的定义中应该做一些其他的事情。在class DefaultCounter(Counter):
def __missing__(self, key):
self[key] = 0
return 0
但是这也没有达到预期的效果(pair_dict["e"]仍然缺少第二个元素)。在
编辑:Counter已经表现为defaultdict(int),但是merge_with不会触发此行为。
正如评论中所建议的,一个Counter已经具备了所需的行为:my_counts = Counter(my_list)
assert my_counts["e"] == 0
问题实际上可能在于merge_with的工作方式:它不会触发所需的defaultdict行为。在
以下测试使用defaultdict而不是Counter来验证这一点:from collections import defaultdict
my_counts = defaultdict(int)
for letter in my_list:
my_counts[letter] += 1
pair_dict = merge_with(tuple, my_dict, my_counts)
assert pair_dict["e"] == ('black',)
因此,在与另一个dict合并之前,必须确保所有键都已在Counter中创建,例如使用this trick。在