590

有没有办法重命名字典键,而无需将其值重新分配给新名称并删除旧名称键;并且不遍历dict键/值?

在 OrderedDict 的情况下,做同样的事情,同时保持那个键的位置。

4

13 回答 13

1001

对于常规字典,您可以使用:

mydict[k_new] = mydict.pop(k_old)

这会将项目移动到字典的末尾,除非k_new已经存在,在这种情况下它将就地覆盖该值。

对于 Python 3.7+ 字典,您还想保留顺序,最简单的方法是重建一个全新的实例。例如,将键重命名2'two'

>>> d = {0:0, 1:1, 2:2, 3:3}
>>> {"two" if k == 2 else k:v for k,v in d.items()}
{0: 0, 1: 1, 'two': 2, 3: 3}

对于 an 也是如此OrderedDict,您不能使用 dict 理解语法,但可以使用生成器表达式:

OrderedDict((k_new if k == k_old else k, v) for k, v in od.items())

正如问题所要求的那样修改密钥本身是不切实际的,因为密钥是可散列的,这通常意味着它们是不可变的并且无法修改。

于 2013-05-10T04:58:21.833 回答
35

使用检查newkey!=oldkey,您可以这样做:

if newkey!=oldkey:  
    dictionary[newkey] = dictionary[oldkey]
    del dictionary[oldkey]
于 2013-05-10T04:54:44.717 回答
20

如果重命名所有字典键:

target_dict = {'k1':'v1', 'k2':'v2', 'k3':'v3'}
new_keys = ['k4','k5','k6']

for key,n_key in zip(target_dict.keys(), new_keys):
    target_dict[n_key] = target_dict.pop(key)
于 2019-06-17T12:29:06.220 回答
12

您可以使用OrderedDict recipeRaymond Hettinger 编写的代码并对其进行修改以添加一个rename方法,但这将是 O(N) 的复杂性:

def rename(self,key,new_key):
    ind = self._keys.index(key)  #get the index of old key, O(N) operation
    self._keys[ind] = new_key    #replace old key with new key in self._keys
    self[new_key] = self[key]    #add the new key, this is added at the end of self._keys
    self._keys.pop(-1)           #pop the last item in self._keys

例子:

dic = OrderedDict((("a",1),("b",2),("c",3)))
print dic
dic.rename("a","foo")
dic.rename("b","bar")
dic["d"] = 5
dic.rename("d","spam")
for k,v in  dic.items():
    print k,v

输出:

OrderedDict({'a': 1, 'b': 2, 'c': 3})
foo 1
bar 2
c 3
spam 5
于 2013-05-10T05:30:11.260 回答
9

在我之前的几个人提到了.pop在单行中删除和创建密钥的技巧。

我个人发现更明确的实现更具可读性:

d = {'a': 1, 'b': 2}
v = d['b']
del d['b']
d['c'] = v

上面的代码返回{'a': 1, 'c': 2}

于 2018-03-07T22:06:18.823 回答
4

其他答案都不错。但是在python3.6中,常规字典也有顺序。所以在正常情况下很难保持key的位置。

def rename(old_dict,old_name,new_name):
    new_dict = {}
    for key,value in zip(old_dict.keys(),old_dict.values()):
        new_key = key if key != old_name else new_name
        new_dict[new_key] = old_dict[key]
    return new_dict
于 2018-08-24T07:47:17.943 回答
3

在 Python 3.6(以后?)中,我会选择以下单线

test = {'a': 1, 'old': 2, 'c': 3}
old_k = 'old'
new_k = 'new'
new_v = 4  # optional

print(dict((new_k, new_v) if k == old_k else (k, v) for k, v in test.items()))

产生

{'a': 1, 'new': 4, 'c': 3}

可能值得注意的是,如果没有print声明,ipython 控制台/jupyter 笔记本会按照他们选择的顺序显示字典......

于 2019-05-07T21:55:29.537 回答
3

假设您要将密钥 k3 重命名为 k4:

temp_dict = {'k1':'v1', 'k2':'v2', 'k3':'v3'}
temp_dict['k4']= temp_dict.pop('k3')
于 2019-05-29T03:18:56.893 回答
1

如果有人想一次重命名所有键,请提供一个包含新名称的列表:

def rename_keys(dict_, new_keys):
    """
     new_keys: type List(), must match length of dict_
    """

    # dict_ = {oldK: value}
    # d1={oldK:newK,} maps old keys to the new ones:  
    d1 = dict( zip( list(dict_.keys()), new_keys) )

          # d1{oldK} == new_key 
    return {d1[oldK]: value for oldK, value in dict_.items()}
于 2019-05-07T15:47:19.643 回答
0

@helloswift123 我喜欢你的功能。这是在一次调用中重命名多个键的修改:

def rename(d, keymap):
    """
    :param d: old dict
    :type d: dict
    :param keymap: [{:keys from-keys :values to-keys} keymap]
    :returns: new dict
    :rtype: dict
    """
    new_dict = {}
    for key, value in zip(d.keys(), d.values()):
        new_key = keymap.get(key, key)
        new_dict[new_key] = d[key]
    return new_dict
于 2019-08-22T23:13:10.310 回答
0

我在上面使用@wim 的答案,在重命名键时使用 dict.pop() ,但我发现了一个问题。循环通过 dict 来更改键,而不将旧键列表与 dict 实例完全分开,导致将新的、更改的键循环到循环中,并丢失一些现有的键。

首先,我是这样做的:

for current_key in my_dict:
    new_key = current_key.replace(':','_')
    fixed_metadata[new_key] = fixed_metadata.pop(current_key)

我发现以这种方式在字典中循环,即使它不应该,字典也会不断地找到键,即新的键,我改变的那些!我需要将实例完全彼此分开,以 (a) 避免在 for 循环中找到我自己更改的键,以及 (b) 找到一些由于某种原因在循环中未找到的键。

我现在正在这样做:

current_keys = list(my_dict.keys())
for current_key in current_keys:
    and so on...

将 my_dict.keys() 转换为列表对于摆脱对不断变化的 dict 的引用是必要的。仅使用 my_dict.keys() 就使我与原始实例联系在一起,并产生了奇怪的副作用。

于 2019-03-21T10:55:16.017 回答
0

我想出了这个不会改变原始字典的函数。此功能也支持字典列表。

import functools
from typing import Union, Dict, List


def rename_dict_keys(
    data: Union[Dict, List[Dict]], old_key: str, new_key: str
):
    """
    This function renames dictionary keys

    :param data:
    :param old_key:
    :param new_key:
    :return: Union[Dict, List[Dict]]
    """
    if isinstance(data, dict):
        res = {k: v for k, v in data.items() if k != old_key}
        try:
            res[new_key] = data[old_key]
        except KeyError:
            raise KeyError(
                "cannot rename key as old key '%s' is not present in data"
                % old_key
            )
        return res
    elif isinstance(data, list):
        return list(
            map(
                functools.partial(
                    rename_dict_keys, old_key=old_key, new_key=new_key
                ),
                data,
            )
        )
    raise ValueError("expected type List[Dict] or Dict got '%s' for data" % type(data))
于 2020-05-28T09:26:40.223 回答
-1

我结合了上述线程的一些答案,并提出了以下解决方案。虽然它很简单,但它可以用作从字典中进行更复杂的键更新的构建块。

test_dict = {'a': 1, 'b': 2, 'c': 3}
print(test_dict)
# {'a': 1, 'b': 2, 'c': 3}
prefix = 'up'
def dict_key_update(json_file):    
    new_keys = []
    old_keys = []
    for i,(key,value) in enumerate(json_file.items()):
        old_keys.append(key)
        new_keys.append(str(prefix) + key) # i have updated by adding a prefix to the 
        # key
    for old_key, new_key in zip(old_keys,new_keys):
        print('old {}, new {}'.format(old_key, new_key))
        if new_key!=old_key:  
           json_file[new_key] = json_file.pop(old_key)
     return json_file

test_dict = dict_key_update(test_dict)
print(test_dict)
# {'upa': 1, 'upb': 2, 'upc': 3}
于 2021-01-11T09:30:36.333 回答