重命名字典键

是否有一种方法重命名字典键,而不重新分配其值为一个新名称和删除旧的名称键;并且没有通过dict键/值迭代?

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

419020 次浏览

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

if newkey!=oldkey:
dictionary[newkey] = dictionary[oldkey]
del dictionary[oldkey]

对于一个普通的字典,你可以使用:

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}

对于OrderedDict也是如此,在这里你不能使用字典理解语法,但你可以使用生成器表达式:

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

正如问题所要求的那样,修改键本身是不切实际的,因为键是hashable,这通常意味着它们是不可变的,不能被修改。

你可以使用Raymond Hettinger编写的OrderedDict recipe,并修改它以添加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

在我之前有一些人提到了在一行程序中删除和创建键的.pop技巧。

我个人认为更显式的实现更具可读性:

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

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

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

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

我使用@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()将我与原始实例绑定在一起,并产生奇怪的副作用。

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

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()}

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笔记本将按照它们选择的顺序显示字典……

假设你想把键k3重命名为k4:

temp_dict = {'k1':'v1', 'k2':'v2', 'k3':'v3'}
temp_dict['k4']= temp_dict.pop('k3')

重命名所有字典键的情况:

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)

@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

我想出了这个函数,它不会改变原来的字典。这个函数也支持字典列表。

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))

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

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}

你可以使用下面的代码:

OldDict={'a':'v1', 'b':'v2', 'c':'v3'}


OldKey=['a','b','c']
NewKey=['A','B','C']


def DictKeyChanger(dict,OldKey,NewKey):
ListAllKey=list(dict.keys())
for x in range(0,len(NewKey)):
dict[NewKey[x]]=dict[OldKey[x]] if OldKey[x] in ListAllKey else None
for x in ListAllKey:
dict.pop(x)
return dict


NewDict=DictKeyChanger(OldDict,OldKey,NewKey)
print(NewDict)#===>>{'A': 'v1', 'B': 'v2', 'C': 'v3'}

注:

  1. 列表OldKey和列表NewKey的长度必须相等。
  2. 列表OldKey的长度必须等于列表NewKey,如果键在OldKey中不存在,则将“noexis”改为如下所示。

例子:

OldDict={'a':'v1', 'b':'v2', 'c':'v3'}
OldKey=['a','b','c','noexis','noexis']
NewKey=['A','B','C','D','E']
NewDict=DictKeyChanger(OldDict,OldKey,NewKey)
print(NewDict)#===>>{'A': 'v1', 'B': 'v2', 'C': 'v3', 'D': None, 'E': None}