我在找到一种优雅的方法来创建一个可以:
的Counter()类时遇到了问题例如:
counter = Counter()
for line in fin:
if a:
counter.incr(key1, 1)
else:
counter.incr(key2, key3, 2)
print counter
理想情况下,我希望得到的结果如下:{key1:20,{key2:{key3:40}}}。但我坚持从键列表创建这个任意嵌套字典。任何帮助表示赞赏。
答案 0 :(得分:0)
有两种可能性。
首先,您可以使用由Counter
s构成的“关键路径”的平面tuple
伪造嵌套关键字:
counter = Counter()
for line in fin:
if a:
counter.incr((key1,), 1)
else:
counter.incr((key2, key3), 2)
但是你需要写一个str
- 替换 - 或者更好的是,一个实现__str__
的包装类。当你在它的时候,你可以轻松编写一个incr
包装器,让你可以使用你想要的API:
def incr(self, *args):
super().incr(args[:-1], args[-1])
或者,您可以在嵌套Counter
之上构建自己的dict
类。 Counter
的代码是用纯Python编写的,而the source非常简单易读。
从您的代码开始,您似乎无需在任何地方访问counter[key2][key3]
等内容,这意味着第一个可能更简单,更合适。
答案 1 :(得分:0)
Counter
对象中唯一可以存在的值是int,您将无法用Counter
表示嵌套字典。
以下是使用普通字典(counter = {}
)执行此操作的一种方法。首先,更新增加单个键的值:
counter[key1] = counter.setdefault(key1, 0) + 1
或者创建嵌套结构的任意键列表:
tmp = counter
for key in key_list[:-1]:
tmp = tmp.setdefault(key, {})
tmp[key_list[-1]] = tmp.setdefault(key_list[-1], 0) + 1
我可能会把它变成以下函数:
def incr(counter, val, *keys):
tmp = counter
for key in keys[:-1]:
tmp = tmp.setdefault(key, {})
tmp[keys[-1]] = tmp.setdefault(keys[-1], 0) + val
示例:
>>> counter = {}
>>> incr(counter, 1, 'a')
>>> counter
{'a': 1}
>>> incr(counter, 2, 'a')
>>> counter
{'a': 3}
>>> incr(counter, 2, 'b', 'c', 'd')
>>> counter
{'a': 3, 'b': {'c': {'d': 2}}}
>>> incr(counter, 3, 'b', 'c', 'd')
>>> counter
{'a': 3, 'b': {'c': {'d': 5}}}
答案 2 :(得分:0)
您可以继承dict
并创建自己的嵌套结构。
这是我尝试写这样的课程:
class Counter(dict):
def incr(self, *args):
if len(args) < 2:
raise TypeError, "incr() takes at least 2 arguments (%d given)" %len(args)
curr = self
keys, count = args[:-1], args[-1]
for depth, key in enumerate(keys, 1):
if depth == len(keys):
curr[key] = curr.setdefault(key, 0) + count
else:
curr = curr.setdefault(key, {})
counter = Counter()
counter.incr('key1', 1)
counter.incr('key2', 'key3', 2)
counter.incr('key1', 7)
print counter #{'key2': {'key3': 2}, 'key1': 8}