如何增加一个值(默认为defaultdicts)?

时间:2018-08-17 15:57:45

标签: python dictionary recursion defaultdict

如果d['a']['b']['c'][1][2][3]d的{​​{1}}且没有代码复制,如何增加defaultdict

defaultdict

在这里我们可以看到我们(在代码中)重复了3次密钥链。

问题:是否可以编写一个函数from collections import defaultdict nested_dict_type = lambda: defaultdict(nested_dict_type) nested_dict = nested_dict_type() # incrementation if type(nested_dict['a']['b']['c']['d'][1][2][3][4][5][6]) != int: nested_dict['a']['b']['c']['d'][1][2][3][4][5][6] = 0 nested_dict['a']['b']['c']['d'][1][2][3][4][5][6] += 1 # ok, now it contains 1 ,该函数将采用inc并完成与上述相同的工作?所以:

nested_dict['a']['b']...[6]

更新(2018年8月20日):

该问题仍然没有答案。很明显,有一些选项“如何做我想做的事”,但是问题很简单:存在“值”,我们将其传递给函数,函数对其进行修改。看来这是不可能的。 只是一个值,没有任何“附加键”等 如果是这样,我们可以使答案更通用吗?

注释:

  1. What is defaultdict of defaultdicts - SO.
  2. 这个问题与“ defaultdict中的整数存储”无关,因此,我不是在寻找叶子上带有int类型的defaultdict的层次结构。
  3. 假设类型(示例中的def inc(x): if type(x) != int: x = 0 x += 1 inc(nested_dict['a']['b']['c']['d'][1][2][3][4][5][6]) # ok, now it contains 1 )事先已知/甚至可以参数化(包括执行int运算符的能力)-问题是如何取消引用对象,将其传递进行修改并在defaultdict的defaultdict上下文中存储
  4. 该问题的答案是否与mutability有关?请参见下面的示例:

示例:

+=

def inc(x): x += 1 d = {'a': int(0)} inc(d['a']) # d['a'] == 0, immutable d = {'a': Int(0)} inc(d['a']) # d['a'] == 1, mutated 在哪里:

Int

2 个答案:

答案 0 :(得分:2)

不是完全而是可变性,更多关于赋值如何执行名称绑定。

x = 0函数中执行inc时,会将新对象绑定到名称x,并且该名称与绑定到该名称的先前对象之间的任何连接都将丢失。这不取决于x是否可变。

但是由于x是可变对象中的一项,我们可以通过将父可变对象以及访问所需项目所需的密钥传递给inc来实现所需的目的。

from collections import defaultdict

nested_dict_type = lambda: defaultdict(nested_dict_type)
nested_dict = nested_dict_type()

# incrementation
def inc(ref, key):
    if not isinstance(ref[key], int):
        ref[key] = 0
    ref[key] += 1

d = nested_dict['a']['b']['c']['d'][1][2][3][4][5]
inc(d, 6)
print(d)

输出

defaultdict(<function <lambda> at 0xb730553c>, {6: 1})

现在我们不绑定新对象,我们只是对现有对象进行突变,因此原始d对象会正确更新。


顺便说一句,深层嵌套的字典使用起来有些痛苦。也许有一种更好的方法来组织数据……但是,无论如何,在使用深层嵌套时可以方便使用的一件事是使用列表或键元组。例如,

q = nested_dict
keys = 'a', 'b', 'c', 'd', 1, 2, 3, 4, 5
for k in keys:
    q = q[k]

q现在是指nested_dict['a']['b']['c']['d'][1][2][3][4][5]

答案 1 :(得分:1)

defaultdict不能有多个默认类型。您有以下选择:

  1. 无限期嵌套defaultdict个对象中的defaultdict个对象;
  2. defaultdict个对象中的int,可能不符合您的需求;
  3. defaultdict中的
  4. defaultdict降至特定级别,并为最后一个级别定义了int,例如d = defaultdict(lambda: defaultdict(int))用于单个嵌套;
  5. 类似于(3),但为了计数,您可以改用collections.Counter,即d = defaultdict(Counter)

如果您总是要下降到设定的水平,我建议使用第3或第4选项。换句话说,标量值将仅在第 n 个级别提供,其中 n 是恒定的。

否则,一个手动选项是让函数执行类型测试。在这种情况下,try / except可能是一个很好的选择。在这里,我们还定义了一种递归算法,使您可以提供键列表而不是定义手动__getitem__调用。

from collections import defaultdict
from functools import reduce
from operator import getitem

nested_dict_type = lambda: defaultdict(nested_dict_type)
d = nested_dict_type()

d[1][2] = 10

def inc(d_in, L):
    try:
        reduce(getitem, L[:-1], d_in)[L[-1]] += 1
    except TypeError:
        reduce(getitem, L[:-1], d_in)[L[-1]] = 1

inc(d, [1, 2])
inc(d, [1, 3])

print(d)

defaultdict({1: defaultdict({2: 11, 3: 1})})