考虑以下代码:

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 :
{'a': ('blue', 3),
 'b': ('green', 2),
 'c': ('yellow', 1),
 'd': ('red', 1),
 'e': ('black',)}

在我的实际案例应用程序中,我需要 pair_dict 中的值成对,所以 pair_dict["e"] 应该是 ('black', 0)

如果我可以让 一个类扩展 Counter 并具有 defaultdict(int) 的良好行为,那将会非常方便。

这很容易做到吗?

我天真地尝试了以下方法:
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"] 仍然是 ('black',)

可能应该在类的定义中做其他事情。

所以我试图适应 this answer :
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',)

因此,必须确保在与其他字典合并之前,所有键都已在 Counter 中创建,例如使用 this trick

最佳答案

不是您所要求的,而是 1 个选项是使用 Counter 键初始化 dict,然后使用 list 更新它,最后使用 dict 理解来获得所需的输出:

>>> c = Counter(my_dict.keys())
>>> c.update(my_list)
>>> {k:(my_dict[k],v-1) for k,v in c.items()}
{'a': ('blue', 3), 'b': ('green', 2), 'c': ('yellow', 1), 'd': ('red', 1), 'e': ('black', 0)}

关于具有 defaultdict(int) 行为的 Python 计数器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47396350/

10-14 09:08