如果字典不存在,则将条目添加到字典中

时间:2012-09-29 04:16:00

标签: python dictionary append

我正在尝试编写一些计算2的幂的代码,但是将它们存储在以10为幂的字典中,因此例如,2 ^ 9将存储为

{0:2, 1:1, 2:5}

你有5 * 10 ^ 2 + 1 * 10 ^ 1 + 2 * 10 ^ 0。

目前,我有类似

的内容
def foo():
    result={0:2}
    for i in range(2,10):
        for p in result.keys():
            result[p]*=2
        for p in result.keys():
            if result[p] / 10 != 0:
                result.setdefault(p+1,result[p]/10)
                result[p] = result[p] % 10

问题是

result.setdefault(p+1,result[p]/10)

它会覆盖result[p+1]中的内容。我知道可以只检查字典,然后根据需要“初始化”新密钥,但是有更优雅的方式可以动态执行吗?我可以将结果初始化为足够长的时间,但由于我不一定知道“足够长”多长时间,因此在我看来更有意义的是在运行中扩展它。

基本上我喜欢

的内容
for p in result.keys():
    if result[p] / 10 != 0:
        if result[p+1] exists:
            result[p+1]+=result[p]/10
        else:
            create result[p+1] and set its value to result[p]/10

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:2)

所以,你每次通过主循环时所做的是:每个数字加倍,然后将额外的数字加到下一个数字。问题是,对于最高位,下一个数字不存在。

所以这是一个解决方案 - 虽然除了2以外的任何其他功能都不会起作用,原因我会到达下面。

def foo():
    result={0:2}
    for i in range(2,10):
        for p in result.keys():
            result[p]*=2
        for p in result.keys()[:]:
            if result[p] / 10 != 0:
                result[p+1] = result.get(p+1, 0) + result[p] / 10
                result[p] = result[p] % 10

原始代码有两处重要更改。

首先,我们必须将[:]添加到第二个result.keys()的末尾,以在循环之前迭代字典的密钥集副本,而不是其当前密钥。原因是如果最后一个数字> 5,我们将在字典中添加一个新密钥,并且在迭代它时不允许这样做。 (为什么?有几个原因,但简单的一个是字典是按任意顺序排列的,每次添加一个键时,整个顺序都可以改变。这在以后也很重要。)

其次,这是您最初的问题:如何避免检查if p+1 in result以确定是存储r_p还是将r_p添加到现有值?

当你处理计数时,使用collection.Counter,它就像dict,只是它只存储整数,任何缺失的键的值都是0.否则,你通常会使用collection.defaultdict,类似于dict,但您可以指定所有缺失键所具有的默认值。使用Counterdefaultdict,您只需要result[p+1] += result[p]/10

但我使用了另一种选择:get上的dict方法,可让您指定默认值。我将在稍后解释原因,但请记住,一般情况下,当您发现自己达到get时,您可能需要defaultdictCounter

所以,现在它将为2的权力运行和工作。但它不适用于其他权力,原因有两个:

首先,我们以随机顺序进行进位。对于2的幂,你可以携带的最多是1,并且1无法影响下一个数字是否携带。 (8不会携带,8 + 1也不会,现在有了获得9的方法。)但是对于任何其他力量,这都不是真的。

在简单测试中,您可能不会注意到这一点,因为当您以空dict开始并添加少量小键时(实际上,至少在CPython 2.7和3.2中)具有小哈希值的密钥,但是以排序顺序对自己进行小的内联哈希)并且不删除任何内容,dict将经常按顺序迭代(和打印)。但总的来说,订单是不可预测的,你不能依赖它。

该问题的解决方案是使用collections.OrderedDict,它按照添加顺序迭代键。这就是为什么我不想使用defaultdictCounter:因为如果你必须切换到OrderedDict,那么你唯一的选择就是get

其次,一旦你的指数超过10,你可能需要携带100.这意味着你必须携带10,这将导致下一个数字随身携带,即使它是0.这意味着我们不能只是复制钥匙提前。例如,假设我们的权力为75.从{0:5, 1:7}开始。将每个数字乘以75到{0:375, 1:525}。现在携带37:{0:5, 1:562}。现在带着56:{0:5, 1:2, 2:56}。因为我们只是迭代原始密钥的副本 - 即[0, 1] - 我们没有机会携带5。

我会由你来解决这个问题。

但是,您可能要考虑的一件事是创建一个新字典,而不是修改旧字典。然后你可以解决所有这些问题。 (作为一般规则,使用纯函数而不是变异状态会遇到很多问题,但当然是以额外复制为代价。)

def double(d):
    result = Counter()
    for p in d:
        result[p] += d[p] % 10
        result[p+1] += d[p] / 10
    return result

digits={0:2}
for i in range(2,10):
    for p in digits:
        digits[p]*=2
    digits = double(digits)

答案 1 :(得分:1)

您可以使用in语法检查是否存在密钥:

for p in result.keys()[:]:
    r_p = result[p] / 10

    if r_p != 0:
        if p + 1 in result:
            result[p + 1] += r_p
        else:
            result[p + 1] = r_p

或者,您可以使用Counter,它会自动执行此操作:

from collections import Counter

result = Counter()

for p in result.keys()[:]:
    r_p = result[p] / 10

    if r_p != 0:
        result[p + 1] += r_p

另外,你的情况有点奇怪。 result[p] / 10 == 0仅在Python 2上为result[p] < 10或在Python 3上为result[p] == 0