【问题标题】:Swapping dictionary keys and values works only on 3 key-value pair dictionary交换字典键和值仅适用于 3 个键值对字典
【发布时间】:2020-10-26 14:41:54
【问题描述】:

这是一个用来交换字典键和值的函数。 {'a': 3} 应该变成 {3: 'a'}

def change_keys_values(d):
    for key in d:
        value = d[key]
        del d[key]
        d[value] = key
     
    return d

我已经意识到这个函数不应该工作,因为我在迭代期间更改了字典键。这是我得到的错误:“迭代期间更改了字典键”。但是,我在三键值对字典上没有收到此错误。因此,虽然{'a': 3, 't': 8, 'r': 2, 'z': 44, 'u': 1, 'b': 4} 导致上述错误,但{'a': 3, 't': 8, 'r': 2} 得到解决而没有任何问题。我正在使用 python 3。这是什么原因造成的?

【问题讨论】:

  • 警告:不要修改您正在迭代的集合。
  • 我明白了。但是,为什么这对 {'a': 3, 't': 8, 'r': 2} 有效?
  • 它将在随机场景中工作,而不是在其他情况下。您需要的是一致的、可预测的工作行为。查看@Miind 的回答

标签: python python-3.x


【解决方案1】:

您绝不能在loop 中修改dictionary。原因在于字典的实现方式。

哈希表

基本上,当您创建字典时,每个项目都使用键的哈希值进行索引。

字典是稀疏实现的

另一个实现细节涉及字典以稀疏方式实现的事实。即,当您创建字典时,内存中有空的地方(称为存储桶)。当您从字典中添加或删除元素时,它可能会达到重新评估字典键哈希值的阈值,从而更改索引。

粗略地说,这两点是你观察到的问题背后的原因。

道德要点:切勿在任何类型的循环中修改字典。

这是一个简单的代码来做你想做的事:

def change_keys_values(d):
    new_dict = {value: key for key, value in d.items()}
    return new_dict

【讨论】:

    【解决方案2】:

    您需要验证这些值是否唯一,之后就没有问题了 :) 但请确保在解析字典时不要更改字典。否则,您可能会遇到一个已更改的索引,该索引会被解释两次甚至更多。我建议制作一个新变量(副本):

    def invert(dict_: dict) -> dict:
        if list(set(dict_.values())) == list(dict_.values()):  # evaluates if "inverting key:value" is possible (if keys are unique)
            return {b: a for a, b in dict_.items()}
        else:
            raise ValueError("Dictionary values contain duplicates. Inversion not possible!")
    
    
    print(invert({"a": 1, "b": 2, "c": 3, "d": 4}))  # works
    
    print(invert({"a": 1, "b": 2, "c": 3, "d": 3}))  # fails
    

    【讨论】:

    • 这并不能回答所提出的问题。您正在创建一个新字典,而问题显然是为什么在一种情况下会出现错误,而不是在另一种情况下出现错误。
    【解决方案3】:

    要解决您的问题,只需遍历副本,而不是原始 dict

    import copy
    
    def change_keys_values(d):
        for key in copy.deepcopy(d):
            value = d[key]
            del d[key]
            d[value] = key
    
        return d
    

    那么使用zip 的好选择是:

    def change_keys_values(d):
        a, b = zip(*d.items())
        d = dict(list(zip(b,a)))
        return d
    

    【讨论】:

    • 他不是在问如何解决这个问题,而是在问为什么在一种情况下会发生错误,而不是在另一种情况下发生。
    • 它看起来很随机 - 它成功了样本dict 的 3 个连续元素,但不是 2 或 4 - 我会坚持“不要修改迭代器,而你循环通过它”行
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-18
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    • 1970-01-01
    • 2013-04-13
    相关资源
    最近更新 更多