사전 키 이름 바꾸기


400

값을 새 이름으로 재 할당하고 이전 이름 ​​키를 제거하지 않고 사전 키 이름을 바꾸는 방법이 있습니까? dict 키 / 값을 반복하지 않고?

OrderedDict의 경우 키 위치를 유지하면서 동일하게 수행하십시오.


7
"새 이름에 값을 다시 할당하지 않고 이전 이름 ​​키를 제거하지 않고"란 정확히 무엇을 의미합니까? 내가 보는 방식, 즉 키 이름 바꾸기의 정의이며 아래의 모든 답변은 값을 다시 할당하고 이전 키 이름을 제거합니다. 당신은 아직 답을 받아들이지 않았으며, 아마도 이것들은 당신이 찾고있는 것을 성취하지 못했을 것입니까?
dbliss

5
버전 번호를 지정해야합니다. Python 3.7부터 언어 사양은 dicts가 삽입 순서를 따르도록 보장합니다 . (A 제외) 당신이 나와있는 문제에 대한 2.x 또는 3.6- 또는 b) 당신이 신경도 백 포트 그 코드 것인지도 OrderedDict 대부분 쓸모있게 윌 OrderedDict 파이썬 3.7에서 중복 될 수 있습니까? ). 3.6으로 돌아가서, 사전 삽입 순서는 CPython 구현에 의해 보장되었지만 언어 사양은 아닙니다.
smci

1
@smci 파이썬 3.7에서 dicts는 삽입 순서를 따르지만 여전히와 다릅니다 OrderedDict. dicts는 평등을 위해 비교 될 때 순서를 무시하고 비교할 OrderedDict때 순서를 고려합니다. 나는 당신이 그것을 설명하는 것에 연결되어 있다는 것을 알고 있지만, 당신의 의견은 그 링크를 읽지 않은 사람들을 오해했을 것이라고 생각했습니다.
Flimm

@Flimm : 맞습니다.하지만 중요한 것은 알 수 없습니다.이 질문은 두 가지 질문을하며 두 번째 부분의 의도가 대체되었습니다. "평등을 위해 비교 될 때 순서를 무시한다는 지시" 예, 순서로 비교하지 않기 때문에 그렇습니다. " OrderedDict비교할 때 순서를 고려 하는 반면 " Ok.3.7 이후에는 아무도 신경 쓰지 않습니다. 나는 OrderedDict거의 쓸모 없다고 주장한다. 왜 그렇지 않은 이유를 분명히 설명 할 수 있는가? 예를 들면 여기 당신이 필요로하지 않는 한 설득력없는reversed()
SMCI

@Flimm : OrderedDict가 3.7 이상 또는 3.7 이전 버전과 호환되지 않는 한 3.7 이상 코드에서 더 이상 사용되지 않는 신뢰할만한 인수를 찾을 수 없습니다. 예를 들어 이것은 전혀 설득력이 없습니다. 특히 "OrderedDict를 사용하면 의도를 전달합니다 ..." 는 완전히 필요한 기술적 부채와 난독 화에 대한 설득력있는 주장입니다. 사람들은 단순히 다시 받아쓰기로 전환해야합니다. 간단합니다.
smci

답변:


712

정기 dict의 경우 다음을 사용할 수 있습니다.

mydict[new_key] = mydict.pop(old_key)

OrderedDict의 경우 이해력을 사용하여 완전히 새로운 것을 만들어야한다고 생각합니다.

>>> OrderedDict(zip('123', 'abc'))
OrderedDict([('1', 'a'), ('2', 'b'), ('3', 'c')])
>>> oldkey, newkey = '2', 'potato'
>>> OrderedDict((newkey if k == oldkey else k, v) for k, v in _.viewitems())
OrderedDict([('1', 'a'), ('potato', 'b'), ('3', 'c')])

dict 키는 일반적 으로 숫자, 문자열 또는 튜플과 같은 변경 불가능한 객체 이므로 키 자체를 수정하는 것은이 질문이하는 것처럼 보이지 않습니다 . 키를 수정하는 대신 값을 새 키에 다시 할당하고 이전 키를 제거하는 것이 파이썬에서 "이름 바꾸기"를 달성하는 방법입니다.


파이썬 3.5의 경우 dict.pop내 테스트를 기반으로 OrderedDict에 사용할 수 있다고 생각 합니다.
Daniel

5
아니요, OrderedDict삽입 순서를 유지하므로 질문에 대한 내용이 아닙니다.
wim

64

한 줄에 가장 좋은 방법 :

>>> d = {'test':[0,1,2]}
>>> d['test2'] = d.pop('test')
>>> d
{'test2': [0, 1, 2]}

3
당신이 있다면 d = {('test', 'foo'):[0,1,2]}?
Petr Fedosov

4
@PetrFedosov, 그렇다면d[('new', 'key')] = d.pop(('test', 'foo'))
Robert Siemer

17
이 답변은 wim의 답변 후 2 년 이 지났는데, 이는 추가 정보없이 똑같은 것을 암시합니다. 내가 무엇을 놓치고 있습니까?
Andras Deak

@AndrasDedict ()와 OrderedDict ()의
차이점

4
2013 년부터 초기 개정에 대한 wim의 답변은 이후 추가 사항 만 있습니다. 순서는 OP의 기준에서만 나옵니다.
Andras Deak

29

check for를 사용하면 다음 newkey!=oldkey과 같은 작업을 수행 할 수 있습니다.

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

4
이것은 아름답게 작동하지만 새 키가 기본적으로 끝에 추가되기 때문에 원래 순서를 유지하지 않습니다 (python3).
szeitlin

2
@ szeitlin dictpython3.6 +가 순서대로 양식을 작성하더라도 이전 버전은 그렇지 않으며 실제로 py3.6 + dicts가 어떻게 변경되었는지에 대한 영향은 아닙니다. OrderedDict주문이 걱정된다면 사용하십시오 .
Granitosaurus

2
감사합니다 @Granitosaurus, 나는 당신이 나에게 그것을 설명 할 필요가 없습니다. 그것은 내 의견의 요점이 아닙니다.
szeitlin

5
이 사실은 전혀 관계가 없습니다 귀하의 의견은 어떤 방식으로, 모양이나 현실에서 아무도 사전 순서에 의존해서는 안 형태로 DICT 주문 사항을 변경 사실 것을 암시 @szeitlin
Granitosaurus

11

모든 사전 키의 이름을 바꾸는 경우 :

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)

1
되어 target_dict.keys()정의와 같은 순서로 보장? 나는 파이썬 dict이 순서가
없다고

어느 시점에서 키를 정렬해야한다고 생각합니다 ...
Espoir Murhabazi

10

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

1
@MERose 모듈 검색 경로 어딘가에 파이썬 파일을 추가하고 가져옵니다 OrderedDict. 그러나 나는 추천 할 것이다 : 상속받은 클래스를 OrderedDict만들고 rename그것에 메소드를 추가 하십시오.
Ashwini Chaudhary 2016 년

OrderedDict와 같이 이중 연결 목록을 사용하도록 다시 작성된 것처럼 보이므로 아직 방법이있을 수 있지만 더 많은 곡예가 필요합니다. :-/
szeitlin

6

저의 몇몇 사람들 .pop은 하나의 라이너에서 키를 삭제하고 생성하는 트릭을 언급했습니다 .

개인적으로보다 명확한 구현이 더 읽기 쉽습니다.

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

위의 코드는 {'a': 1, 'c': 2}


1

다른 답변은 꽤 좋지만 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

1

파이썬 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 노트북은 선택한 순서대로 사전을 제시 한다는 점에 주목할 가치가 있습니다 .


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

-1

키의 이름을 바꿀 때 dict.pop ()과 함께 위의 @wim 대답을 사용하고 있지만 문제가 있습니다. dict 인스턴스에서 이전 키 목록을 완전히 분리하지 않고 dict를 통해 키를 변경하면 새로운 키가 순환되고 루프로 변경되어 기존 키가 누락되었습니다.

우선, 나는 이렇게했다 :

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

나는 이런 식으로 dict을 통해 순환하는 것을 발견했다. 사전은 그것이 바뀌지 않아야 할 때조차도 키를 찾는 것을 발견했다. (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 ()를 사용하면 이상한 부작용으로 원래 인스턴스에 묶여 있습니다.


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

-1

@ 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

-2

키 k3의 이름을 k4로 바꾸고 싶다고 가정하십시오.

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

1
작동하지 않습니까? ... temp_dict [ 'k4'] = temp_dict.pop ( 'k3')?
DougR

키 의 값을 참조하려고 TypeError: 'dict' object is not callable하면 If를 반환합니다 . 괄호가 아닌 대괄호를 사용해야합니다. 그러나 이것은 사전에 새 키를 추가하고 요청에 따라 기존 키의 이름을 바꾸지 않습니다. temp_dict('k3')k3
재스민
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.