list는 sort 메서드가 있다.
numbers = [93, 86, 11, 68, 70]
numbers.sort()
print(numbers)
[11, 68, 70, 86, 93]
sort가 객체를 처리하는 방법에 대해 알아보자
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.5),
Tool('끌', 0.25),
]
sort 메서드가 호출하는 객체 비교 특별 메서드가 정의돼 있지 않으므로 이런 타입의 객체를 정렬할 수 없다.
tools.sort()
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-16-934c749d7824> in <module> ----> 1 tools.sort() TypeError: '<' not supported between instances of 'Tool' and 'Tool'
tools[0]
Tool('수준계', 3.5)
tools
[Tool('수준계', 3.5), Tool('해머', 1.25), Tool('스크류드라이버', 0.5), Tool('끌', 0.25)]
print(tools[0])
Tool('수준계', 3.5)
정렬에 사용하고 싶은 애트리뷰트가 객체에 들어 있는 경우가 많다.
sort 에는 key라는 파라미터가 존재하는데 함수를 사용해야 한다.
print('미정렬:', repr(tools))
tools.sort(key=lambda x: x.name)
print('\n정렬: ', tools)
미정렬: [Tool('수준계', 3.5), Tool('해머', 1.25), Tool('스크류드라이버', 0.5), Tool('끌', 0.25)] 정렬: [Tool('끌', 0.25), Tool('수준계', 3.5), Tool('스크류드라이버', 0.5), Tool('해머', 1.25)]
tools.sort(key=lambda x: x.weight)
print('무게순 정렬:', tools)
무게순 정렬: [Tool('끌', 0.25), Tool('스크류드라이버', 0.5), Tool('해머', 1.25), Tool('수준계', 3.5)]
다음 예제는 lower 메서드를 사용해 리스트에 들어 있는 장소 이름을 소문자로 변환함으로써 첫 글자가 대문자든 소문자든 구분하지 않고 알파벳 순으로 비교한다.
places = ['home', 'work', 'New York', 'Paris']
places.sort()
print('대소문자 구분:', places)
places.sort(key=lambda x: x.lower())
print('대소문자 무시:', places)
대소문자 구분: ['New York', 'Paris', 'home', 'work'] 대소문자 무시: ['home', 'New York', 'Paris', 'work']
여러 기준을 사용하고 싶을때, 즉, 리스트가 있는데 weight로 먼저 정렬한 다음에 name으로 정렬하는 방법
power_tools = [
Tool('드릴', 4),
Tool('원형 톱', 5),
Tool('착암기', 40),
Tool('연마기', 4),
]
기본적으로 튜플을 사용하는것, 튜플은 비교 가능하며 순서가 있음. sort에 필요한 lt 정의가 들어있음.
saw = (5, '원형 톱')
jackhammer = (40, '착암기')
assert not (jackhammer < saw)
jackhammer < saw
False
두 튜플의 첫 번째 위치에 있는 값이 서로 같으면 튜플의 비교 메서드는 두 번째 위치에 있는 값을 비교하고.. 반복..
drill = (4, '드릴')
sander = (4, '연마기')
assert drill[0] == sander[0] # 무게가 같다
assert drill[1] < sander[1] # 알파벳순으로 볼 때 더 작다
assert drill < sander # 그러므로 드릴이 더 먼저다
두 애트리뷰트를 우선순위에 따라 튜플에 넣어 반환하는 key 함수 정의
power_tools.sort(key=lambda x: (x.weight, x.name))
print(power_tools)
[Tool('드릴', 4), Tool('연마기', 4), Tool('원형 톱', 5), Tool('착암기', 40)]
튜플을 반환하는 key 함수의 한 가지 제약 사항은 모든 비교 기준의 정렬 순서가 같아야함
power_tools.sort(key=lambda x: (x.weight, x.name),
reverse=True) # 모든 비교 기준을 내림차순으로 만든다
print(power_tools)
[Tool('착암기', 40), Tool('원형 톱', 5), Tool('연마기', 4), Tool('드릴', 4)]
숫자 값의 경우 - 연산자를 사용해 정렬 방향을 혼합 할 수 있다.
power_tools.sort(key=lambda x: (-x.weight, x.name))
print(power_tools)
[Tool('착암기', 40), Tool('원형 톱', 5), Tool('드릴', 4), Tool('연마기', 4)]
power_tools.sort(key=lambda x: (x.weight, -x.name),
reverse=True)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-30-41e1c1504b5b> in <module> ----> 1 power_tools.sort(key=lambda x: (x.weight, -x.name), 2 reverse=True) <ipython-input-30-41e1c1504b5b> in <lambda>(x) ----> 1 power_tools.sort(key=lambda x: (x.weight, -x.name), 2 reverse=True) TypeError: bad operand type for unary -: 'str'
다른 타입은 이런식으로 사용이 불가 하기 때문에 안정적인 정렬 알고리즘을 제공한다.
리스트 타입의 sort 메서드는 key 함수가 반환하는 값이 서로 같은 경우 리스트에 들어 있던 원래 순서를 그대로 유지한다.
따라서 다른 기준으로 sort를 여러번 호출해도 된다.
power_tools.sort(key=lambda x: x.name) # name 기준 오름차순
power_tools.sort(key=lambda x: x.weight, # weight 기준 내림차순
reverse=True)
print(power_tools)
[Tool('착암기', 40), Tool('원형 톱', 5), Tool('드릴', 4), Tool('연마기', 4)]
power_tools.sort(key=lambda x: x.name)
print(power_tools)
[Tool('드릴', 4), Tool('연마기', 4), Tool('원형 톱', 5), Tool('착암기', 40)]
power_tools.sort(key=lambda x: x.weight,
reverse=True)
print(power_tools)
[Tool('착암기', 40), Tool('원형 톱', 5), Tool('드릴', 4), Tool('연마기', 4)]