선언 된 것과 동일한 순서로 키 / 값을 유지하는 방법은 무엇입니까?


320

특정 순서로 선언 한 사전이 있고 항상 그 순서대로 유지하고 싶습니다. 키 / 값은 실제로 값을 기준으로 순서를 유지할 수 없으므로 선언 된 순서대로 원합니다.

사전이 있다면 :

d = {'ac': 33, 'gw': 20, 'ap': 102, 'za': 321, 'bs': 10}

그것을 보거나 반복하면 순서가 맞지 않습니다. 파이썬이 키 / 값을 선언 한 명시 적 순서를 유지할 수있는 방법이 있습니까?

답변:


229

Python 3.6부터 표준 dict유형은 기본적으로 삽입 순서를 유지합니다.

정의

d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}

소스 코드에 나열된 순서대로 키가있는 사전이 생성됩니다.

이것은 희소 해시 테이블에 정수가있는 간단한 배열을 사용하여 달성되었습니다. 여기서 해당 정수는 키-값 쌍 (및 계산 된 해시)을 저장하는 다른 배열로 색인됩니다. 후자의 배열은 항목을 삽입 순서대로 저장하기 때문에 전체 조합은 실제로 Python 3.5 및 이전 버전에서 사용 된 구현보다 적은 메모리를 사용합니다. 자세한 내용은 Raymond Hettinger원본 아이디어 게시물 을 참조하십시오.

3.6에서 이것은 여전히 ​​구현 세부 사항으로 간주되었습니다. Python 3.6 설명서 의 새로운 기능을 참조하십시오 .

이 새로운 구현의 순서 유지 측면은 구현 세부 사항으로 간주되며 의존해서는 안됩니다 (향후 변경 될 수 있지만 언어 사양을 변경하기 전에 몇 가지 릴리스에 대해 언어 로이 새로운 dict 구현을 갖는 것이 바람직합니다 현재와 ​​미래의 모든 파이썬 구현에 대한 순서 유지 의미를 강제하기 위해; 이것은 또한 임의의 반복 순서가 여전히 유효한 이전 버전의 언어와의 하위 호환성을 유지하는 데 도움이됩니다 (예 : Python 3.5).

Python 3.7은이 구현 세부 사항을 언어 스펙으로 높이 므로 이제 dict해당 버전 이상과 호환되는 모든 Python 구현에서 순서 를 유지 해야합니다 . BDFL선언을 참조하십시오 .

collections.OrderedDict()클래스 는 표준 dict유형 외에 추가 기능을 제공하기 때문에 특정 경우에 클래스 를 계속 사용할 수 있습니다 . 이러한 인만큼 가역 (이는 확장 뷰 객체 ) 및 (비아 재정렬지지 move_to_end()방식 ).


불행히도 이것은 사전 작성 과 관련이 없습니다 . 코드의 예제에서와 같이 지정된 사전은 동일한 순서를 유지한다고 보장되지 않습니다. 즉, 빈 dict을 작성하고 순서를 제어하려면 각 요소를 수동으로 삽입해야합니다.
naught101

8
@ naught101 : 아니,이 않습니다 DICT 작성에 적용됩니다. Python 3.7 이상에서는 질문에 표시된대로 dict 디스플레이를 사용하여 해당 키를 순서대로 나열 할 수 있습니다. 때문에 기록 같이 키 - 값 쌍은 왼쪽에서 오른쪽으로 삽입되어 해당 언어의 사양을 보장 : 키 쉼표로 구분 된 시퀀스 / 데이텀 쌍 주어지면, 그들로부터 평가가 사전의 항목을 정의하는 좌우 . dict()문서는 도 예를 포함한다.
Martijn Pieters

175
from collections import OrderedDict
OrderedDict((word, True) for word in words)

포함

OrderedDict([('He', True), ('will', True), ('be', True), ('the', True), ('winner', True)])

값이 True(또는 다른 불변의 객체 인 경우) 다음을 사용할 수도 있습니다.

OrderedDict.fromkeys(words, True)

2
물론 '불변'부분은 파이썬이 시행 할 수있는 단단하고 빠른 규칙은 아니라는 점에 주목할 필요가있다.
lvc

11
OrderedDict(FUTURE=[], TODAY=[], PAST=[])언급 된 경우 다음과 같은 솔루션이 작동 OrderedDict([('FUTURE', []), ('TODAY', []), ('PAST', [])])하지 않습니다.
andilabs

2
@andi 또 다른 문제가 있습니다 .jsonify를 사용할 때 json 데이터를 생성 할 때 OrderedDict가 순서를 잃어버린 것 같습니다.
tyan

github.com/pallets/flask/issues/974 이것은 문제를 해결하는데 사용될 수 있습니다.
tyan

5
Python3.7은 기본적으로 dict 순서로되어 있습니다. mail.python.org/pipermail/python-dev/2017-December/151283.html
sertsedat

167

이론적 인 부분을 설명하는 대신 간단한 예를 들겠습니다.

>>> from collections import OrderedDict
>>> my_dictionary=OrderedDict()
>>> my_dictionary['foo']=3
>>> my_dictionary['aol']=1
>>> my_dictionary
OrderedDict([('foo', 3), ('aol', 1)])
>>> dict(my_dictionary)
{'foo': 3, 'aol': 1}

16
Dict 유형과 같이 OrderedDict를 대량 할당하는 방법이 있습니까?
tyan

2
OrderedDict실제로 문제를 해결하지만 ...이 특정 예에서는 표준 사전을 사용하여 정확히 동일한 결과를 얻습니다
Tonechas

2
@ Tonchas : 방금 표준 사전으로 예제를 시도해 보았으므로 {'aol': 1, 'foo': 3}좋은 예라고 생각합니다.
twasbrillig

4
모두에게 교훈이 있습니다. 파이썬의 예측 가능한 해싱이 보안 취약점을 일으킬 수 있다는 사실이 발견되었습니다 (2.4 릴리스 부근에서 생각 합니다 ). 따라서 동일한 코드를 두 번 실행해도 표준에서 동일한 순서를 지정할 것이라는 보장은 없습니다 dict.
holdenweb

1
@tyan OrderedDict.update()키-값 쌍을 포함하는 iterable로 호출 할 수 있습니다 : d1.upate([(key1, val1), (key2, val2)]).
Ruud Althuizen

37

이 답변은 python3.7 이전의 Python 버전에 적용됩니다. CPython 3.6은 대부분의 상황에서 구현 세부 사항으로 삽입 순서를 유지합니다. Python3.7부터는 구현시 반드시 삽입 순서를 준수해야한다고 선언되었습니다.


파이썬 사전은 순서가 없습니다. 정렬 된 사전을 원하면 collections.OrderedDict를 시도하십시오 .

OrderedDict는 python 2.7의 표준 라이브러리에 도입되었습니다. 이전 버전의 python을 사용하는 경우 ActiveState 에서 주문 된 사전에 대한 레시피를 찾을 수 있습니다 .


위의 @martijn의 게시물을 참조하십시오. python 3.6부터 dict는 삽입 순서를 지원합니다.
tpk

13

사전은 검색을 효율적으로하는 순서를 사용하며이를 변경할 수 없습니다.

객체 목록 (간단한 경우에는 2 요소 튜플 또는 클래스)을 사용하고 항목을 끝에 추가 할 수 있습니다. 그런 다음 선형 검색을 사용하여 항목을 찾을 수 있습니다.

또는 순서를 유지하기 위해 작성된 다른 데이터 구조를 작성하거나 사용할 수 있습니다.


사전은 효율적인 검색 순서를 사용합니다. 마지막으로 누군가 지적했습니다.
scharette

7

OrderedDict를 작동시키는 방법을 알아 내려고 노력 하면서이 게시물을 보았습니다. PyDev for Eclipse는 OrderedDict를 전혀 찾을 수 없었으므로 주문을 원하는대로 사전 키 값의 튜플을 작성하기로 결정했습니다. 내 목록을 출력해야 할 때 튜플의 값을 반복하고 튜플에서 반복 된 '키'를 사전에 꽂아 필요한 순서대로 값을 검색했습니다.

예:

test_dict = dict( val1 = "hi", val2 = "bye", val3 = "huh?", val4 = "what....")
test_tuple = ( 'val1', 'val2', 'val3', 'val4')
for key in test_tuple: print(test_dict[key])

그것은 귀찮은 일이지만 시간이 지났으며 내가 생각해 낸 해결 방법입니다.

참고 : 목록 목록은 순서가 지정되고 색인이 작성되며 사전과 다른 구조이므로 다른 사람이 제안한 목록 접근 방식은 실제로 이해가되지 않습니다.


훌륭한 솔루션. 항상 같은 순서로 파일에 json을 쓰는 데 사용합니다.
Hrvoje T

6

사전으로 원하는 것을 실제로 할 수는 없습니다. 사전이 이미 d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}작성되었습니다. 이미 만들어진 순서대로 유지할 방법이 없다는 것을 알았습니다. 내가 한 것은 객체 대신 json 파일을 만드는 것입니다.

{"ac":33,"gw":20,"ap":102,"za":321,"bs":10}

나는 사용했다 :

r = json.load(open('file.json'), object_pairs_hook=OrderedDict)

그런 다음 사용 :

print json.dumps(r)

확인합니다.


1
그렇다면 왜리스트에서 OrderedDict로 시작하지 않습니까? JSON 파일은 실제로 여기에 아무것도 추가하지 않습니다.
Martijn Pieters

예, 목록은 순서를 유지하는 데 더 유용하지만 사전 정렬에 대한 질문과 관련이 있습니다. 사전 사용의 한계에 대해 사람들에게 알리고 어떤 이유로 사전을 사용해야 할 경우 가능한 해결 방법을 제공하십시오.
nealous3

1
그러나 그 부분은 이미 2012 년으로 거슬러 올라가는 훨씬 더 오래된 답변으로 덮여 있습니다.
Martijn Pieters

3
from collections import OrderedDict
list1 = ['k1', 'k2']
list2 = ['v1', 'v2']
new_ordered_dict = OrderedDict(zip(list1, list2))
print new_ordered_dict
# OrderedDict([('k1', 'v1'), ('k2', 'v2')])

더 이상 dict이 아닌 주요 문제는 튜플 목록입니다.
Oleg

2

또 다른 대안은 dataframedict-like 구조로 항목의 순서와 색인 위치를 보장하므로 Pandas를 사용 하는 것입니다.


1

일반적으로, 당신은 사전처럼 동작합니다은 주로 방법을 구현하는 것이 클래스를 디자인 할 수 있습니다 __contains__, __getitem__, __delitem__, __setitem__좀 더. 해당 클래스는 원하는 동작을 가질 수 있습니다 (예 : 키에 대해 정렬 된 반복자 권한 부여) ...


1

특정 순서로 사전을 원하면 목록의 목록을 만들 수도 있습니다. 목록의 목록은 첫 번째 항목이 키이고 두 번째 항목이 값이며이 예와 같습니다.

>>> list =[[1,2],[2,3]]
>>> for i in list:
...     print i[0]
...     print i[1]

1
2
2
3

7
전체 모음을 검색하지 않고 키로 항목을 조회 할 수 없기 때문에 "사전"이 아닙니다 (O (n) 소요).
BHSPitMonkey

1
예, 사전은 아니지만 상황에 따라 원래 포스터의 문제에 대한 유효한 솔루션을 제공 할 수 있습니다.
SunSparc

그는 우리가 원하는 방식을 정확하게 말하지 않았으며 항상 주문할 수 있기를 원했습니다.
pelos

1

장고 프로젝트를 개발할 때 비슷한 문제가 발생했습니다. 이전 버전의 파이썬을 실행하고 있었기 때문에 OrderedDict를 사용할 수 없었으므로 해결책은 Django의 SortedDict 클래스를 사용하는 것이 었습니다.

https://code.djangoproject.com/wiki/SortedDict

예를 들어

from django.utils.datastructures import SortedDict
d2 = SortedDict()
d2['b'] = 1
d2['a'] = 2
d2['c'] = 3

참고 :이 답변은 원래 2011 년입니다. Python 버전 2.7 이상에 액세스 할 수 있다면 now 표준에 액세스 할 수 있어야 collections.OrderedDict합니다.이 스레드의 다른 사람들이 많은 예제를 제공했습니다.


0

사전에했던 것과 같은 일을 할 수 있습니다.

목록을 만들고 빈 사전을 만드십시오.

dictionary_items = {}
fields = [['Name', 'Himanshu Kanojiya'], ['email id', 'hima@gmail.com']]
l = fields[0][0]
m = fields[0][1]
n = fields[1][0]
q = fields[1][1]
dictionary_items[l] = m
dictionary_items[n] = q
print dictionary_items
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.