Python 딕셔너리 리스트 정렬 방법 2가지

딕셔너리가 담겨있는 리스트를 키 값에 따라 정렬해야 하는 경우가 있죠. Python 딕셔너리 리스트 정렬 방법을 살펴보겠습니다.

Python 딕셔너리 리스트 정렬 방법

DB에서 데이터를 읽어오는 경우에 딕셔너리 형태의 항목으로 이루어진 리스트를 정렬해야 하는 경우가 생깁니다. sorted()를 이용하는 두 가지 방법에 대해 알아보도록 하겠습니다.

sorted() 사용법

람다(lambda) 식 사용 방법

우선 sorted() 함수에 key를 lambda 식으로 입력해 주는 방식이 있습니다. 람다 식을 이용해서 user[‘name’]을 정렬의 key로 설정하는 방식입니다.

users = [
    {'name': 'David', 'age': 29},
    {'name': 'Sarah', 'age': 34},
    {'name': 'John', 'age': 21},
    {'name': 'David', 'age': 53},
    {'name': 'Kevin', 'age': 38},
    {'name': 'David', 'age': 38},
    {'name': 'Abraham', 'age': 21},
]
sorted_list = sorted(users, key=lambda user: (user['name']))
print(*sorted_list, sep="\n")
Python

user[‘name’]을 기준으로 오름차순 정렬을 했기 때문에 아래 그림과 같이 사용자 이름을 기준으로 정렬된 것을 확인할 수 있습니다.

그림 1. Python 딕셔너리 리스트 정렬: user['name'] 기준으로 오름차순 정렬
그림 1. Python 딕셔너리 리스트 정렬: user[‘name’] 기준으로 오름차순 정렬

itemgetter() 사용방법

딕셔너리를 리스트로 가지고 있는 경우에는 itemgetter()를 이용해서 딕셔너리의 키 값을 입력해 줌으로써 정렬할 수 있습니다.

from operator import itemgetter

sorted_list = sorted(users, key=itemgetter('name'))
Python

정렬한 결과는 아래 그림 2와 같으며 그림 1과도 결과가 동일함을 확인할 수 있습니다.

그림 2. Python 딕셔너리 리스트 정렬: itemgetter() 이용한 정렬
그림 2. Python 딕셔너리 리스트 정렬: itemgetter() 이용한 정렬

중복조건 정렬

이번에는 user[‘name’] 순으로 오름차순 정렬하면서, user[‘age’] 순으로 오름차순 정렬해 보려고 합니다. 이 경우에는 다음 코드와 같이 람다식으로 설정하는 튜플에 정렬하고자 하는 키를 추가로 설정해 주면 됩니다.

sorted_list = sorted(users, key=lambda user: (user['name'], user['age']))
Python

위의 그림 1을 보면 이름이 David인 딕셔너리가 3개인 것을 알 수 있습니다. 그림 2에서는 이름순 정렬 + 나이순 정렬까지 된 결과로 그림 1과는 다른 것을 확인할 수 있습니다.

그림 3. Python 딕셔너리 리스트 정렬: user['name'], user['age'] 순서로 오름차순 정렬
그림 3. Python 딕셔너리 리스트 정렬: user[‘name’], user[‘age’] 순서로 오름차순 정렬

그런데, 아래와 같이 user[‘name’]은 내림차순으로, user[‘age’]를 오름차순으로 정렬하고 싶다면 어떻게 해야 할까요?

Sarah, 34
Kevin, 38
John, 21
David, 29
David, 38
David, 53
Abraham, 21

잘 보시면 아래에 user[‘age’] 앞에 음수 부호(-)를 붙여서 반대 방향을 표현하도록 했습니다. 그리고, 전체적인 정렬을 역정렬 즉, 내림차순으로 정렬하게 했습니다. user[‘name’]으로 내림차순 정렬하되, -user[‘age’]로 정렬하니까 내림차순의 내림차순은 오름차순이 되겠습니다.

sorted_list = sorted(users, key=lambda user: (user['name'], -user['age']), reverse=True)
Python

보시면 위에서 기대했던 것과 같은 결과를 가져오는 것을 볼 수 있습니다.

그림 4. Python 딕셔너리 리스트 정렬: 복합조건 정렬(이름 내림차순, 나이 오름차순)
그림 4. Python 딕셔너리 리스트 정렬: 복합조건 정렬(이름 내림차순, 나이 오름차순)

그런데 문제가 있습니다. 음수 부호(-)를 이용해서 정렬하는 것은 숫자값인 경우에만 이용할 수 있습니다. 즉, 해당 키를 이용하는 데이터가 문자열인 경우에는 사용할 수 없다는 것입니다.

이번에는 조금 다른 결과를 기대해 보겠습니다. 나이로 오름차순 정렬을 하되, 이름은 내림차순 정렬을 원하는 경우입니다.

John, 21
Abraham, 21
David, 29
Sarah, 34
Kevin, 38
David, 38
David, 53

마찬가지로 음수부호(-)를 이용해서 정렬이 가능합니다.

sorted_list = sorted(users, key=lambda user: (-user['age'], user['name']), reverse=True)
Python

이번에도 원하는 결과를 얻을 수 있었습니다.

그림 5. Python 딕셔너리 리스트 정렬: 복합조건 정렬(나이 오름차순, 이름 내림차순)
그림 5. Python 딕셔너리 리스트 정렬: 복합조건 정렬(나이 오름차순, 이름 내림차순)

하지만, reverse를 True로 하면서 음수부호를 사용하다보면 혼란스러워지기 쉽습니다. 왜냐하면 부정의 부정이 참이라는 것은 알지만 그걸 고려해서 코드를 작성해야 하며, 누군가가 해당 코드를 해석해야 하는 상황이라면 해석하는데 시간도 더 오래 걸릴 것입니다.

그리고 무엇보다도 심각한 상황은 정렬를 원하는 두 가지 키의 값들이 모두 문자열인 경우에는 음수부호로 혼합 정렬을 할 수 없으며, 문자열에 음수 부호를 사용하면 아래와 같이 TypeError: bad operand type for unary -: ‘str’ 오류 메시지를 만나게 됩니다.

그림 6. 문자열의 키에 음수부호를 사용하는 경우 발생하는 오류
그림 6. 문자열의 키에 음수부호를 사용하는 경우 발생하는 오류

이 문제를 해결할 수 있는 방법을 함께 살펴보겠습니다.

오름차순, 내림차순 혼합정렬

그건 다름 아닌 sort() 메서드 또는 sorted() 함수를 중복해서 사용하는 방법입니다.

설명이 어렵고 복잡해 질 수 있으니 코드를 통해서 직접 살펴보겠습니다.

sorted_list = sorted(users, key=lambda user: user['age'])
Python

위의 코드를 실행한 결과는 아래와 같습니다.

그림 7. Python 딕셔너리 리스트 정렬 1차(나이 오름차순)
그림 7. Python 딕셔너리 리스트 정렬 1차(나이 오름차순)

이제 이 상태에서 user[‘name’]을 내림차순으로 정렬해 보겠습니다.

sorted_list = sorted(users, key=lambda user: user['age'])
sorted_list = sorted(sorted_list, key=lambda user: user['name'], reverse=True)
Python

위의 코드를 실행한 결과는 아래와 같습니다. 최종적으로 이름을 내림차순으로 정렬하되 나이는 오름차순으로 정렬하게 된 것입니다.

그림 8. Python 딕셔너리 리스트 정렬 2차(이름 내림차순, 나이 오름차순)
그림 8. Python 딕셔너리 리스트 정렬 2차(이름 내림차순, 나이 오름차순)

앞에서 람다식에서 튜플을 통해 조건을 중복으로 줄 때에는 튜플의 앞에 올수록 해당 조건의 정렬이 최우선 순위가 되어 정렬되는 것이지만, 지금과 같이 중복해서 list.sort() 메서드 또는 sorted() 함수를 이용하는 경우에는 가장 마지막에 실행하는 sort() 또는 sorted()에서 지정한 키가 최우선순위가 되는 것입니다.

따라서 나이를 오름차순으로 정렬하되, 이름은 내림차순으로 정렬하고 싶다면 아래 코드와 같이 이름에 대한 정렬을 먼저 해 준 후, 나이에 대한 정렬을 실행해 주면 됩니다.

sorted_list = sorted(users, key=lambda user: user['name'], reverse=True)
sorted_list = sorted(sorted_list, key=lambda user: user['age'])
Python

결과는 나이를 오름차순으로 하되, 이름이 역순으로 정렬된 것을 확인할 수 있습니다. 21살의 John과 Abraham, 그리고 38살의 Kevin과 David을 통해서 확인할 수 있습니다.

그림 9. Python 딕셔너리 리스트 정렬 2차(나이 오름차순, 이름 내림차순)
그림 9. Python 딕셔너리 리스트 정렬 2차(나이 오름차순, 이름 내림차순)

이러한 방법이 이용가능한 까닭은 먼저 정렬을 실행한 결과의 순서가 이후 정렬되는 조건에 영향을 받지 않으면 우선 정렬한 내용이 유지되기 때문입니다.

이 방법을 사용하면 문자열도 부담 없이 복합 정렬이 가능할 뿐만 아니라 코드의 이해도 보다 쉬워집니다. 협업하는 경우에 코드의 가독성이 올라가면 생산성도 올라가는 것 아시죠? 음수부호는 당장 쓰기에 때론 편할 수 있지만, reverse=True와 함께 사용하는 음수부호는 인지 부하를 높이게 되니 지양하는 편이 좋겠습니다.

관련 자료

Python의 Sorting Techniques 문서를 참고했습니다.

같이 읽으면 좋은 글

Leave a Comment