IT/언어

[python] 순서를 지정할 수 있는 dictionary ; OrderedDict의 사용법

개발자 두더지 2022. 7. 26. 21:00
728x90

일본의 한 블로그 글을 번역한 포스트입니다. 오역 및 의역, 직역이 있을 수 있으며 틀린 내용은 지적해주시면 감사하겠습니다.

 

 Python의 사전형(dict형 오브젝트) 데이터는 요소의 순서를 갖고 있지 않다. Python의 3.6버전부터는 순서를 가지고 잇지만, 구현하는 방식에 의존하므로 구현하는 방식에 따르게 된다. 3.7 버전부터는 언어 사양 자체적으로 순서가진  사전형 데이터가 되는듯하다.

 한편 표준 라이브러리인 collections 모듈에는 순서를 가진 사전형 데이터를 사용할 수 있도록 OrderDict가 준비되어 있다.  collections 모듈을 import한다. 표준 라이브러리에 포함되어 있으므로 별도의 설치는 필요하지 않다. 

import collections

 import 구문은 아래와 같이 작성하면, collections.는 생략가능하다.

from collections import OrderedDict

 이번 포스트의 주제인 OrderDict의 사용법에 대해서 다음의 내용을 설명하고자 한다.

  • OrderDict 오브젝트의 작성
  • OrderDict는 dict의 서브 클래스
  • 요소를 맨 앞/ 맨 끝으로 이동시키기
  • 임의의 위치에 새로운 요소를 추가하기
  • 요소를 변경하기(정렬)
  • 요소를 키 혹은 값으로 정렬하기

 

 

OrderDict 오브젝트의 작성


 컨스트럭터 collections.Ordercit()으로 OrderDict 오브젝트를 생성할 수 있다. 다음의 코드는 빈 OrderDcit 오브젝트를 작성하여 값을 추가하는 방법이다.

od = collections.OrderedDict()

od['k1'] = 1
od['k2'] = 2
od['k3'] = 3

print(od)
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])

 컨스트럭터에 인수를 지정하는 것도 가능하다.

 키워드 인수나 키와 값 페어의 시퀀스(튜플(key, value)등)의 시퀀스등을 사용할 수 있다. 후자의 경우(키와 값 페어) 리스트도 튜플이어도 OK이다.

print(collections.OrderedDict(k1=1, k2=2, k3=3))
print(collections.OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)]))
print(collections.OrderedDict((['k1', 1], ['k2', 2], ['k3', 3])))
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])

 3.5버전까지는 키워드 인수라면 순서가 유지되지 않았지만, 3.6버전부터는 유지되도록 됐다. 보통의 사전(dict형 오브젝트)도 컨스트럭터에 전달하지만, dict형이 순서를 유지하지 않도록 구현된 경우, 생성된 OrderDict도 순서가 유지되지 않는다.

print(collections.OrderedDict({'k1': 1, 'k2': 2, 'k3': 3}))
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])

 

 

OrderDict는 dict의 서브 클래스


 OrderDict는 dict의 서브클래스이다.

print(issubclass(collections.OrderedDict, dict))
# True

 OrderDict도 dict와 동일한 메소드를 가지고 있어, 요소의 취득이나 변경, 추가, 삭제등의 방법이 기존의 dict와 동일하다.

print(od['k1'])
# 1

od['k2'] = 200
print(od)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3)])

od.update(k4=4, k5=5)
print(od)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3), ('k4', 4), ('k5', 5)])

del od['k4'], od['k5']
print(od)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3)])

 

 

요소를 맨 앞/ 맨 끝으로 이동시키기


 OrderDict의 독자적인 메소드 move_to_end()를 사용하여 요소를 맨 앞 혹은 맨 끝으로 이동시킬 수 있다. 키를 제 1인 인수로 지정한다. 기본적으로 맨 끝으로 이동하며, 제 2인수인 last를 False로 하면 맨 앞으로 이동하게 된다.

od.move_to_end('k1')
print(od)
# OrderedDict([('k2', 200), ('k3', 3), ('k1', 1)])

od.move_to_end('k1', False)
print(od)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3)])

 

 

임의의 위치에 새로운 요소를 추가하기


 임의의 위치에 새로운 요소를 추가한 OrderDict 오브젝트를 새롭게 작성할 수 있다.

  • items() 메소드로 취득할 수 있는 뷰 오브젝트를 list()으로 리스트화
  • 리스트의 insert() 메소드로 키와 값의 페어인 튜플(key, value)를 추가
  • 컨스트럭터 collections.OrderDict()에 전달해, 새로운 오브젝트를 작성

 위와 같은 흐름이다.

l = list(od.items())
print(l)
# [('k1', 1), ('k2', 200), ('k3', 3)]

l.insert(1, ('kx', -1))
print(l)
# [('k1', 1), ('kx', -1), ('k2', 200), ('k3', 3)]

od = collections.OrderedDict(l)
print(od)
# OrderedDict([('k1', 1), ('kx', -1), ('k2', 200), ('k3', 3)])

 insert()는 첫 번째 인수에 삽입할 위치, 두 번째 인수에는 요소를 지정한다.

 예에서는 원래의 변수에 새로운 오브젝트를 대입하여, 원래 오브젝트 자체에 새로운 요소를 추가하지 않았다.

 

 

요소를 변경하기(정렬)


 요소의 변경은 다음과 같은 순서로 구현된다.

  • items() 메소드로 얻을 수 있는 뷰 오브젝트를 list()으로 리스트화
  • 리스트의 요소를 바꾸기
  • 컨스트럭터 collections.OrderDict()에 전달해, 새로운 오브젝트를 작성
l = list(od.items())
print(l)
# [('k1', 1), ('kx', -1), ('k2', 200), ('k3', 3)]

l[0], l[2] = l[2], l[0]
print(l)
# [('k2', 200), ('kx', -1), ('k1', 1), ('k3', 3)]

od = collections.OrderedDict(l)
print(od)
# OrderedDict([('k2', 200), ('kx', -1), ('k1', 1), ('k3', 3)])

 키를 지정하여 바꾸고 싶은 경우는 아래와 같이 키의 리스트에서 index() 메소드로 인덱스(위치)를 획득한다.

l = list(od.items())
k = list(od.keys())
print(k)
# ['k2', 'kx', 'k1', 'k3']

print(k.index('kx'))
# 1

l[k.index('kx')], l[k.index('k3')] = l[k.index('k3')], l[k.index('kx')]
print(l)
# [('k2', 200), ('k3', 3), ('k1', 1), ('kx', -1)]

od = collections.OrderedDict(l)
print(od)
# OrderedDict([('k2', 200), ('k3', 3), ('k1', 1), ('kx', -1)])

 

 

요소를 키 혹은 값으로 정렬하기


 items() 메소드로 획득할 수 있는 뷰 오브젝트를 바탕으로 키와 값의 페어의 튜플(keym value)의 리스트로 만들어, 컨스트럭터 collections.OrderDict()에 전달해, 새로운 오브젝트를 작성한다.

 내장함수 sorted()의 인수 key에 튜플(key,value)의 키 혹은 값을 전달하는 무명 함수(람다식)를 지정하여 정렬한다.

 역순으로 하고 싶은 경우 sorted()의 인수 reverse를 True로 한다.

print(od)
# OrderedDict([('k2', 200), ('k3', 3), ('k1', 1), ('kx', -1)])

od_sorted_key = collections.OrderedDict(
    sorted(od.items(), key=lambda x: x[0])
)
print(od_sorted_key)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3), ('kx', -1)])

od_sorted_value = collections.OrderedDict(
    sorted(od.items(), key=lambda x: x[1], reverse=True)
)
print(od_sorted_value)
# OrderedDict([('k2', 200), ('k3', 3), ('k1', 1), ('kx', -1)])

참고자료

https://note.nkmk.me/python-collections-ordereddict/

728x90