sourcecode

사전 키 이름 바꾸기

copyscript 2022. 9. 25. 00:16
반응형

사전 키 이름 바꾸기

새 이름에 값을 재할당하거나 이전 이름 키를 제거하거나 dict 키/값을 반복하지 않고 사전 키의 이름을 변경할 수 있는 방법이 있습니까?

OrderedDict의 경우 해당 키의 위치를 유지하면서 동일한 작업을 수행합니다.

일반 딕트의 경우 다음을 사용할 수 있습니다.

mydict[k_new] = mydict.pop(k_old)

다음 경우를 제외하고 항목을 dict의 끝으로 이동합니다.k_new는 이미 존재하며, 이 경우 값을 덮어씁니다.

순서를 추가로 유지하고 싶은 Python 3.7+ dict의 경우, 가장 간단한 것은 완전히 새로운 인스턴스를 재구축하는 것입니다.예를 들어, 키 이름 변경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}

같은 일이 일어나면OrderedDictdict 이해 구문은 사용할 수 없지만 생성자 표현식은 사용할 수 있습니다.

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

질문에서 요구하는 와 같이 키 자체를 수정하는 것은 비현실적입니다.이는 보통 키가 불변하고 수정할 수 없음을 의미합니다.

다음에 대한 체크 사용newkey!=oldkey다음과 같이 할 수 있습니다.

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

모든 사전 키의 이름을 변경하는 경우:

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)

Raymond 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

저 전에 몇 분께서....pop원라이너에서 키를 삭제하고 작성하는 트릭입니다.

저는 개인적으로 보다 명확한 구현이 더 읽기 쉽다고 생각합니다.

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

위의 코드가 반환됩니다.{'a': 1, 'c': 2}

다른 대답들은 꽤 좋습니다.그러나 python3.6에서는 일반 dict에도 순서가 있습니다.그래서 정상적인 경우에는 키의 위치를 유지하는 것이 어렵습니다.

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

키 k3의 이름을 k4로 변경한다고 가정합니다.

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

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}

주의할 필요가 있을 것 같습니다.printipython 콘솔/노트북이 사전을 선택한 순서대로 표시...

모든 키의 이름을 한 번에 변경하려는 경우 새 이름이 포함된 목록을 제공합니다.

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

원본 사전을 음소거하지 않는 이 기능을 생각해 냈습니다.이 기능은 사전 목록도 지원합니다.

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

키의 이름을 변경할 때 위의 @wim의 답변을 dict.pop()과 함께 사용하고 있는데 gotcha를 찾았습니다.이전 키 목록을 dict 인스턴스에서 완전히 분리하지 않고 키를 변경하기 위해 dict를 순환하면 새 키가 순환되고 루프가 변경되어 기존 키가 손실됩니다.

우선, 저는 이렇게 했습니다.

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

이런 식으로 딕트를 반복하면서 사전은 새 키, 즉 내가 바꾼 키를 찾지 말아야 할 때에도 계속해서 키를 찾아낸다는 것을 알게 되었다.(a) for loop에서 변경된 키를 찾지 않기 위해 (b) 루프 내에서 찾을 수 없는 키를 찾기 위해 인스턴스를 서로 완전히 분리해야 했습니다.

지금 하고 있는 중입니다.

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

my_dict.keys()를 목록으로 변환하는 것은 변경되는 dict에 대한 참조를 없애기 위해 필요했습니다.my_dict.keys()를 사용하는 것만으로, 이상한 부작용과 함께 원래의 인스턴스에 묶이게 되었습니다.

@helloswift123 당신의 기능이 마음에 듭니다.다음으로 1개의 콜에서 여러 키의 이름을 변경하기 위한 변경을 나타냅니다.

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

다음 코드를 사용할 수 있습니다.

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 '붙입니다.

예:

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}

의 스레드에서 몇 가지 답변을 조합하여 아래의 해결책을 제시합니다.단순하지만 사전에서 보다 복잡한 키 업데이트를 수행하기 위한 구성 요소로 사용할 수 있습니다.

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}

언급URL : https://stackoverflow.com/questions/16475384/rename-a-dictionary-key

반응형