如何更改Python字典中条目的键?


只需2步即可轻松完成:

dictionary[new_key] = dictionary[old_key]
del dictionary[old_key]

或者一步:

dictionary[new_key] = dictionary.pop(old_key)

如果字典[old_key]未定义,将引发KeyError。注意,这将删除字典[old_key]。

>>> dictionary = { 1: 'one', 2:'two', 3:'three' }
>>> dictionary['ONE'] = dictionary.pop(1)
>>> dictionary
{2: 'two', 3: 'three', 'ONE': 'one'}
>>> dictionary['ONE'] = dictionary.pop(1)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
KeyError: 1

您可以将相同的值与许多键相关联,或者只是删除一个键并重新添加具有相同值的新键。

例如,如果你有键->值:

red->1
blue->2
green->4

没有理由不能添加紫色->2或删除红色->1并添加橙色->1


没有直接的方法做到这一点,但你可以删除然后分配

d = {1:2,3:4}

d[newKey] = d[1]
del d[1]

或者做大量的键改变:

d = dict((changeKey(k), v) for k, v in d.items())

流行与新鲜

>>>a = {1:2, 3:4}
>>>a[5] = a.pop(1)
>>>a
{3: 4, 5: 2}
>>> 

如果你想更改所有的键:

d = {'x':1, 'y':2, 'z':3}
d1 = {'x':'a', 'y':'b', 'z':'c'}

In [10]: dict((d1[key], value) for (key, value) in d.items())
Out[10]: {'a': 1, 'b': 2, 'c': 3}

如果你想改变单键: 你可以选择上面的任何一个建议。


因为键是字典用来查找值的,所以实际上不能更改它们。您可以做的最接近的事情是保存与旧键相关联的值,删除它,然后使用替换键和保存的值添加一个新条目。其他几个答案说明了实现这一目标的不同方式。


我还没有看到确切的答案:

dict['key'] = value

您甚至可以对对象属性执行此操作。 通过这样做,将它们编入字典:

dict = vars(obj)

然后你可以像操作字典一样操作对象属性:

dict['attribute'] = value

在python 2.7及更高版本中,您可以使用字典理解: 这是我在使用DictReader读取CSV时遇到的一个例子。用户已经在所有列名后面加上了':'

ori_dict ={“key1:”:1、“key2:”:2,“key3:”:3}

在键中去掉后面的':':

Corrected_dict = {k.replace(':', "): v for k, v in ori_dict.items()}


如果你有一个复杂的字典,这意味着字典中有一个字典或列表:

myDict = {1:"one",2:{3:"three",4:"four"}}
myDict[2][5] = myDict[2].pop(4)
print myDict

Output
{1: 'one', 2: {3: 'three', 5: 'four'}}

以防一次换了所有的钥匙。 我在这里阻塞钥匙。

a = {'making' : 1, 'jumping' : 2, 'climbing' : 1, 'running' : 2}
b = {ps.stem(w) : a[w] for w in a.keys()}
print(b)
>>> {'climb': 1, 'jump': 2, 'make': 1, 'run': 2} #output

转换字典中的所有键

假设这是你的字典:

>>> sample = {'person-id': '3', 'person-name': 'Bob'}

将示例字典键中的所有破折号转换为下划线:

>>> sample = {key.replace('-', '_'): sample.pop(key) for key in sample.keys()}
>>> sample
>>> {'person_id': '3', 'person_name': 'Bob'}

d = {1:2,3:4}

假设我们想要改变列表元素p=['a', 'b']的键值。 下面的代码可以做到:

d=dict(zip(p,list(d.values()))) 

我们得到

{'a': 2, 'b': 4}

这个函数获得一个字典,另一个字典指定如何重命名键;它返回一个新的字典,带有重命名的键:

def rekey(inp_dict, keys_replace):
    return {keys_replace.get(k, k): v for k, v in inp_dict.items()}

测试:

def test_rekey():
    assert rekey({'a': 1, "b": 2, "c": 3}, {"b": "beta"}) == {'a': 1, "beta": 2, "c": 3}

方法,如果有人想替换多级字典中出现的所有键。

函数检查字典是否有特定的键,然后遍历子字典并递归调用该函数:

def update_keys(old_key,new_key,d):
    if isinstance(d,dict):
        if old_key in d:
            d[new_key] = d[old_key]
            del d[old_key]
        for key in d:
            updateKey(old_key,new_key,d[key])

update_keys('old','new',dictionary)

这将小写你所有的字典键。即使你有嵌套的字典或列表。您可以执行类似的操作来应用其他转换。

def lowercase_keys(obj):
  if isinstance(obj, dict):
    obj = {key.lower(): value for key, value in obj.items()}
    for key, value in obj.items():         
      if isinstance(value, list):
        for idx, item in enumerate(value):
          value[idx] = lowercase_keys(item)
      obj[key] = lowercase_keys(value)
  return obj 
json_str = {"FOO": "BAR", "BAR": 123, "EMB_LIST": [{"FOO": "bar", "Bar": 123}, {"FOO": "bar", "Bar": 123}], "EMB_DICT": {"FOO": "BAR", "BAR": 123, "EMB_LIST": [{"FOO": "bar", "Bar": 123}, {"FOO": "bar", "Bar": 123}]}}

lowercase_keys(json_str)


Out[0]: {'foo': 'BAR',
 'bar': 123,
 'emb_list': [{'foo': 'bar', 'bar': 123}, {'foo': 'bar', 'bar': 123}],
 'emb_dict': {'foo': 'BAR',
  'bar': 123,
  'emb_list': [{'foo': 'bar', 'bar': 123}, {'foo': 'bar', 'bar': 123}]}}

完整解决方案的示例

声明一个json文件,其中包含你想要的映射

{
  "old_key_name": "new_key_name",
  "old_key_name_2": "new_key_name_2",
}

加载它

with open("<filepath>") as json_file:
    format_dict = json.load(json_file)

创建此函数来使用映射格式化字典

def format_output(dict_to_format,format_dict):
  for row in dict_to_format:
    if row in format_dict.keys() and row != format_dict[row]:
      dict_to_format[format_dict[row]] = dict_to_format.pop(row)
  return dict_to_format

注意pop的位置: 将你想要删除的键放在pop()之后 orig_dict['AAAAA'] = orig_dict.pop('A')

orig_dict = {'A': 1, 'B' : 5,  'C' : 10, 'D' : 15}   
# printing initial 
print ("original: ", orig_dict) 

# changing keys of dictionary 
orig_dict['AAAAA'] = orig_dict.pop('A')
  
# printing final result 
print ("Changed: ", str(orig_dict)) 


我在下面写了这个函数,您可以将当前键名的名称更改为新名称。

def change_dictionary_key_name(dict_object, old_name, new_name):
    '''
    [PARAMETERS]: 
        dict_object (dict): The object of the dictionary to perform the change
        old_name (string): The original name of the key to be changed
        new_name (string): The new name of the key
    [RETURNS]:
        final_obj: The dictionary with the updated key names
    Take the dictionary and convert its keys to a list.
    Update the list with the new value and then convert the list of the new keys to 
    a new dictionary
    '''
    keys_list = list(dict_object.keys())
    for i in range(len(keys_list)):
        if (keys_list[i] == old_name):
            keys_list[i] = new_name

    final_obj = dict(zip(keys_list, list(dict_object.values()))) 
    return final_obj

假设一个JSON,你可以调用它,并通过以下行重命名它:

data = json.load(json_file)
for item in data:
    item = change_dictionary_key_name(item, old_key_name, new_key_name)

在这里可以找到从列表到字典键的转换:https://www.geeksforgeeks.org/python-ways-to-change-keys-in-dictionary/


对于熊猫,你可以有这样的东西,

from pandas import DataFrame
df = DataFrame([{"fruit":"apple", "colour":"red"}])
df.rename(columns = {'fruit':'fruit_name'}, inplace = True)
df.to_dict('records')[0]
>>> {'fruit_name': 'apple', 'colour': 'red'}


用下划线替换字典键中的空格,我使用这个简单的路由…

for k in dictionary.copy():
    if ' ' in k:
        dictionary[ k.replace(' ', '_') ] = dictionary.pop(k, 'e r r')

或者只是dictionary。pop(k)注意'e r r',它可以是任何字符串,如果键不在字典中,就会成为新的值,从而能够替换它,这在这里不可能发生。参数是可选的,在其他类似的代码中,KeyError可能会被击中,添加的arg会避免它,但可以创建一个新的键'e rr '或任何你设置的值。

.copy()避免…字典在迭代过程中改变了大小。

.keys()不需要,k是每个键,k在我的头脑中代表键。

(我使用v3.7)

关于字典pop()的信息

上面循环的一行代码是什么?


你可以使用iff/else字典理解。此方法允许您在一行中替换任意数量的键,并且不需要更改所有键。

key_map_dict = {'a':'apple','c':'cat'}
d = {'a':1,'b':2,'c':3}
d = {(key_map_dict[k] if k in key_map_dict else k):v  for (k,v) in d.items() }

返回{“苹果”:1、“b”:2,“猫”:3}


我只是要帮我妻子做一些python类的事情,所以我写了这段代码来告诉她如何做。正如标题所示,它只替换键名。这是非常罕见的,你必须替换一个键名,并保持字典的顺序完整,但我还是想分享,因为这篇文章是当你搜索它时谷歌返回的,即使它是一个非常老的线程。

代码:

dictionary = {
    "cat": "meow",
    "dog": "woof",
    "cow": "ding ding ding",
    "goat": "beh"
}


def countKeys(dictionary):
    num = 0
    for key, value in dictionary.items():
        num += 1
    return num


def keyPosition(dictionary, search):
    num = 0
    for key, value in dictionary.items():
        if key == search:
            return num
        num += 1


def replaceKey(dictionary, position, newKey):
    num = 0
    updatedDictionary = {}
    for key, value in dictionary.items():
        if num == position:
            updatedDictionary.update({newKey: value})
        else:
            updatedDictionary.update({key: value})
        num += 1
    return updatedDictionary


for x in dictionary:
    print("A", x, "goes", dictionary[x])
    numKeys = countKeys(dictionary)

print("There are", numKeys, "animals in this list.\n")
print("Woops, that's not what a cow says...")

keyPos = keyPosition(dictionary, "cow")
print("Cow is in the", keyPos, "position, lets put a fox there instead...\n")
dictionary = replaceKey(dictionary, keyPos, "fox")

for x in dictionary:
    print("A", x, "goes", dictionary[x])

输出:

A cat goes meow
A dog goes woof
A cow goes ding ding ding
A goat goes beh
There are 4 animals in this list.

Woops, that's not what a cow says...
Cow is in the 2 position, lets put a fox there instead...

A cat goes meow
A dog goes woof
A fox goes ding ding ding
A goat goes beh

为了有效地保持有序情况(另一个是平凡的,删除旧的和添加新的),避免有序字典需要重构(至少部分地),我把一个类(OrderedDictX)放在一起,它扩展了OrderedDict,并允许您高效地进行键更改,即在O(1)复杂度中。该实现还可以针对现在已排序的内置dict类进行调整。

它使用2个额外的字典来重新映射已更改的键(“外部”-例如,当它们出现在用户外部时)到底层OrderedDict中的键(“内部”)-字典将只保存已更改的键,因此只要没有更改键,它们将为空。

性能测量:

import timeit
import random

# Efficiency tests
from collections import MutableMapping

class OrderedDictRaymond(dict, MutableMapping):
    def __init__(self, *args, **kwds):
        if len(args) > 1:
            raise TypeError('expected at 1 argument, got %d', len(args))
        if not hasattr(self, '_keys'):
            self._keys = []
        self.update(*args, **kwds)

    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
        dict.__delitem__(self, key)

    def clear(self):
        del self._keys[:]
        dict.clear(self)

    def __setitem__(self, key, value):
        if key not in self:
            self._keys.append(key)
        dict.__setitem__(self, key, value)

    def __delitem__(self, key):
        dict.__delitem__(self, key)
        self._keys.remove(key)

    def __iter__(self):
        return iter(self._keys)

    def __reversed__(self):
        return reversed(self._keys)

    def popitem(self):
        if not self:
            raise KeyError
        key = self._keys.pop()
        value = dict.pop(self, key)
        return key, value

    def __reduce__(self):
        items = [[k, self[k]] for k in self]
        inst_dict = vars(self).copy()
        inst_dict.pop('_keys', None)
        return (self.__class__, (items,), inst_dict)

    setdefault = MutableMapping.setdefault
    update = MutableMapping.update
    pop = MutableMapping.pop
    keys = MutableMapping.keys
    values = MutableMapping.values
    items = MutableMapping.items

    def __repr__(self):
        pairs = ', '.join(map('%r: %r'.__mod__, self.items()))
        return '%s({%s})' % (self.__class__.__name__, pairs)

    def copy(self):
        return self.__class__(self)

    @classmethod
    def fromkeys(cls, iterable, value=None):
        d = cls()
        for key in iterable:
            d[key] = value
        return d

class obj_container:
    def __init__(self, obj) -> None:
        self.obj = obj

def change_key_splice(container, k_old, k_new):
    od = container.obj
    container.obj = OrderedDict((k_new if k == k_old else k, v) for k, v in od.items())

def change_key_raymond(container, k_old, k_new):
    od = container.obj
    od.rename(k_old, k_new)

def change_key_odx(container, k_old, k_new):
    odx = container.obj
    odx.change_key(k_old, k_new)

NUM_ITEMS = 20000
od_splice = OrderedDict([(x, x) for x in range(NUM_ITEMS)])
od_raymond = OrderedDictRaymond(od_splice.items())
odx = OrderedDictX(od_splice.items())
od_splice, od_raymond, odx = [obj_container(d) for d in [od_splice, od_raymond, odx]]
assert odx.obj == od_splice.obj
assert odx.obj == od_raymond.obj
# Pick randomly half of the keys to change
keys_to_change = random.sample(range(NUM_ITEMS), NUM_ITEMS//2)
print(f'OrderedDictX: {timeit.timeit(lambda: [change_key_odx(odx, k, k+NUM_ITEMS) for k in keys_to_change], number=1)}')
print(f'OrderedDictRaymond: {timeit.timeit(lambda: [change_key_raymond(od_raymond, k, k+NUM_ITEMS) for k in keys_to_change], number=1)}')
print(f'Splice: {timeit.timeit(lambda: [change_key_splice(od_splice, k, k+NUM_ITEMS) for k in keys_to_change], number=1)}')
assert odx.obj == od_splice.obj
assert odx.obj == od_raymond.obj

和结果:

OrderedDictX: 0.06587849999999995
OrderedDictRaymond: 1.1131364
Splice: 1165.2614647

正如预期的那样,拼接方法非常慢(但也没想到它会慢那么多),并且使用大量内存,O(N) Raymond解决方案也较慢,在本例中为17倍。

当然,这个解决方案是O(1),与O(N) OrderedDictRaymond相比,随着字典大小的增加,时间差变得更加明显,例如,对于5倍多的元素(100000),O(N)现在慢了100倍:

NUM_ITEMS = 100000
OrderedDictX: 0.3636919999999999
OrderedDictRaymond: 36.3963971

以下是代码,如果您看到问题或有改进建议,请评论,因为这可能仍然容易出错。

from collections import OrderedDict


class OrderedDictX(OrderedDict):
    def __init__(self, *args, **kwargs):
        # Mappings from new->old (ext2int), old->new (int2ext).
        # Only the keys that are changed (internal key doesn't match what the user sees) are contained.
        self._keys_ext2int = OrderedDict()
        self._keys_int2ext = OrderedDict()
        self.update(*args, **kwargs)

    def change_key(self, k_old, k_new):
        # Validate that the old key is part of the dict
        if not self.__contains__(k_old):
            raise Exception(f'Cannot rename key {k_old} to {k_new}: {k_old} not existing in dict')

        # Return if no changing is actually to be done
        if len(OrderedDict.fromkeys([k_old, k_new])) == 1:
            return

        # Validate that the new key would not conflict with another one
        if self.__contains__(k_new):
            raise Exception(f'Cannot rename key {k_old} to {k_new}: {k_new} already in dict')

        # Change the key using internal dicts mechanism
        if k_old in self._keys_ext2int:
            # Revert change temporarily
            k_old_int = self._keys_ext2int[k_old]
            del self._keys_ext2int[k_old]
            k_old = k_old_int
            # Check if new key matches the internal key
            if len(OrderedDict.fromkeys([k_old, k_new])) == 1:
                del self._keys_int2ext[k_old]
                return

        # Finalize key change
        self._keys_ext2int[k_new] = k_old
        self._keys_int2ext[k_old] = k_new

    def __contains__(self, k) -> bool:
        if k in self._keys_ext2int:
            return True
        if not super().__contains__(k):
            return False
        return k not in self._keys_int2ext

    def __getitem__(self, k):
        if not self.__contains__(k):
            # Intentionally raise KeyError in ext2int
            return self._keys_ext2int[k]
        return super().__getitem__(self._keys_ext2int.get(k, k))

    def __setitem__(self, k, v):
        if k in self._keys_ext2int:
            return super().__setitem__(self._keys_ext2int[k], v)
        # If the key exists in the internal state but was renamed to a k_ext,
        # employ this trick: make it such that it appears as if k_ext has also been renamed to k
        if k in self._keys_int2ext:
            k_ext = self._keys_int2ext[k]
            self._keys_ext2int[k] = k_ext
            k = k_ext
        return super().__setitem__(k, v)

    def __delitem__(self, k):
        if not self.__contains__(k):
            # Intentionally raise KeyError in ext2int
            del self._keys_ext2int[k]
        if k in self._keys_ext2int:
            k_int = self._keys_ext2int[k]
            del self._keys_ext2int[k]
            del self._keys_int2ext[k_int]
            k = k_int
        return super().__delitem__(k)

    def __iter__(self):
        yield from self.keys()

    def __reversed__(self):
        for k in reversed(super().keys()):
            yield self._keys_int2ext.get(k, k)

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, dict):
            return False
        if len(self) != len(other):
            return False
        for (k, v), (k_other, v_other) in zip(self.items(), other.items()):
            if k != k_other or v != v_other:
                return False
        return True

    def update(self, *args, **kwargs):
        for k, v in OrderedDict(*args, **kwargs).items():
            self.__setitem__(k, v)

    def popitem(self, last=True) -> tuple:
        if not last:
            k = next(iter(self.keys()))
        else:
            k = next(iter(reversed(self.keys())))
        v = self.__getitem__(k)
        self.__delitem__(k)
        return k, v

    class OrderedDictXKeysView:
        def __init__(self, odx: 'OrderedDictX', orig_keys):
            self._odx = odx
            self._orig_keys = orig_keys

        def __iter__(self):
            for k in self._orig_keys:
                yield self._odx._keys_int2ext.get(k, k)

        def __reversed__(self):
            for k in reversed(self._orig_keys):
                yield self._odx._keys_int2ext.get(k, k)

    class OrderedDictXItemsView:
        def __init__(self, odx: 'OrderedDictX', orig_items):
            self._odx = odx
            self._orig_items = orig_items

        def __iter__(self):
            for k, v in self._orig_items:
                yield self._odx._keys_int2ext.get(k, k), v

        def __reversed__(self):
            for k, v in reversed(self._orig_items):
                yield self._odx._keys_int2ext.get(k, k), v

    def keys(self):
        return self.OrderedDictXKeysView(self, super().keys())

    def items(self):
        return self.OrderedDictXItemsView(self, super().items())

    def copy(self):
        return OrderedDictX(self.items())    


# FIXME: move this to pytest
if __name__ == '__main__':
    MAX = 25
    items = [(i+1, i+1) for i in range(MAX)]
    keys = [i[0] for i in items]
    d = OrderedDictX(items)

    # keys() before change
    print(list(d.items()))
    assert list(d.keys()) == keys
    # __contains__ before change
    assert 1 in d
    # __getitem__ before change
    assert d[1] == 1
    # __setitem__ before change
    d[1] = 100
    assert d[1] == 100
    d[1] = 1
    assert d[1] == 1
    # __delitem__ before change
    assert MAX in d
    del d[MAX]
    assert MAX not in d
    d[MAX] = MAX
    assert MAX in d
    print('== Tests before key change finished ==')

    # change_key and __contains__
    assert MAX-1 in d
    assert MAX*2 not in d
    d.change_key(MAX-1, MAX*2)
    assert MAX-1 not in d
    assert MAX*2 in d
    # items() and keys()
    items[MAX-2] = (MAX*2, MAX-1)
    keys[MAX-2] = MAX*2
    assert list(d.items()) == items
    assert list(d.keys()) == keys
    print(list(d.items()))
    # __getitem__
    assert d[MAX*2] == MAX-1
    # __setitem__
    d[MAX*2] = MAX*3
    items[MAX-2] = (MAX*2, MAX*3)
    keys[MAX-2] = MAX*2
    assert list(d.items()) == items
    assert list(d.keys()) == keys
    # __delitem__
    del d[MAX]
    items = items[:-1]
    keys = keys[:-1]
    assert list(d.items()) == items
    assert list(d.keys()) == keys
    d[MAX] = MAX
    items.append((MAX, MAX))
    keys.append(MAX)
    # __iter__
    assert list(d) == keys
    # __reversed__
    print(list(reversed(d.items())))
    assert list(reversed(d)) == list(reversed(keys))
    assert list(reversed(d.keys())) == list(reversed(keys))
    assert list(reversed(d.items())) == list(reversed(items))
    # pop_item()
    assert d.popitem() == (MAX, MAX)
    assert d.popitem() == (MAX*2, MAX*3)
    items = items[:-2]
    keys = keys[:-2]
    assert list(d.items()) == items
    assert list(d.keys()) == keys
    # update()
    d.update({1: 1000, MAX-2: MAX*4})
    items[0] = (1, 1000)
    items[MAX-3] = (MAX-2, MAX*4)
    assert list(d.items()) == items
    assert list(d.keys()) == keys
    # move_to_end()
    d.move_to_end(1)
    items = items[1:] + [items[0]]
    keys = keys[1:] + [keys[0]]
    assert list(d.items()) == items
    assert list(d.keys()) == keys
    # __eq__
    d.change_key(1, 2000)
    other_d = OrderedDictX(d.items())
    assert d == other_d
    assert other_d == d