Book/파이썬 코딩의 기술
[BW 14] 복잡한 기준을 사용해 정렬할 때는 key 파라미터를 사용하라
31514
2024. 10. 22. 16:11
다음과 같은 클래스가 있다고 가정해보고 tools 를 정의했다.
class Tool:
def __init__(self, name, weight):
self.name = name
self.weight = weight
def __repr__(self):
return f'Tool({self.name!r}, {self.weight})'
tools = [
Tool('수준계', 3.5),
Tool('해머', 1.25),
Tool('스크류드라이버', 0.25),
Tool('끌', 0.25),
]
tools 에 담긴 여러 인스턴스를 sort()를 통해 정렬할 수 있을까?
비교 연산자를 지원하지 않는 오류가 발생한다.
Traceback (most recent call last):
File "/Users/dev/Study/devcourse_aws/test.py", line 18, in <module>
tools.sort()
TypeError: '<' not supported between instances of 'Tool' and 'Tool'
하지만 정렬 기준으로 객체의 속성을 전달한다면 비교 가능하다.
tools.sort(key=lambda x: x.name)
print(tools)
>>>
[Tool('끌', 0.25), Tool('수준계', 3.5), Tool('스크류드라이버', 0.25), Tool('해머', 1.25)]
만약 여러 기준을 사용해 정렬해야 한다면 어떻게 해야할까?
튜플을 사용하면 가장 쉽게 할 수 있다.
drill = (4, '드릴')
hammer = (4, '해머')
print(drill < hammer)
>>>
True
튜플을 활용하면 다음과 같이 sort 에도 적용할 수 있다.
tools.sort(key=lambda x: (x.weight, x.name))
print(tools)
>>>
[Tool('끌', 0.25), Tool('스크류드라이버', 0.25), Tool('해머', 1.25), Tool('수준계', 3.5)]
한 가지 제약 사항은 모든 비교 기준의 정렬 순서가 같아야 한다는 점이다.
예를 들어, x.weight에만 reverse를 걸 수 없다.
reverse를 걸면 x.weight과 x.name 모두 걸린다.
tools.sort(key=lambda x: (x.weight, x.name), reverse=True)
print(tools)
>>>
[Tool('수준계', 3.5), Tool('해머', 1.25), Tool('스크류드라이버', 0.25), Tool('끌', 0.25)]
x.weight에만 reverse를 걸고 싶다면 두 가지 방법이 있다.
첫 번째는 x.weight이 숫자이므로 부호 반전을 사용하는 것이다.
tools.sort(key=lambda x: (-x.weight, x.name))
print(tools)
>>>
[Tool('수준계', 3.5), Tool('해머', 1.25), Tool('끌', 0.25), Tool('스크류드라이버', 0.25)]
두 번째는 파이썬이 제공하는 안정적인 정렬 알고리즘을 사용하는 것이다.
리스트 타입의 sort 메서드는 key 함수가 반환하는 값이 서로 같은 경우 리스트에 들어 있던 원래의 순서를 그대로 유지한다.
tools.sort(key=lambda x: x.name)
tools.sort(key=lambda x: x.weight, reverse=True)
print(tools)
>>>
[Tool('수준계', 3.5), Tool('해머', 1.25), Tool('끌', 0.25), Tool('스크류드라이버', 0.25)]
하지만 부호 반전을 사용할 수 있다면 가독성을 위해 선호한다.