list 내장 타입에 들어있는 리스트의 원소를 여러 기준에 따라 정렬하는 메서드
자연스러운 순서가 있어야하는 경우, 필요한 메서드를 정의하면 별도의 인자를 넘기지 않고 sort 가능
sort는 리스트의 내용을 원소 타입에 따른 오름차순으로 정렬
sort메서드는 내장타입(문자열, 부동소수점)등에 잘 작동
sort메서드가 호출하는 객체 비교 특별 메서드가 정의되지 않으면 객체 정렬 불가
*예시1: 자연스러운 순서로 오름차순 정렬
numbers = [93,86,11,68,70]
numbers.sort()
print(numbers) # [11,68,70,86,93]
*예시2: sort메서드 자연스럽게 순서 정하기(in 내장타입)
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),
]
*예시3: sort메서드가 호출 시 특별 메서드가 정의되지 않으면 객체 정렬 불가
tools.sort()
#Traceback...
#TypeError: '<' not supported between instances of 'Tool' and 'Tool'
실제로는 저희가 만든 객체가 여러 가지 순서를 지원해야하는 경우가 더 많습니다.
*예시1: lambda 키워드로 함수를 정의함 for name따라 정렬
print('미정렬:', repr(tools)) #미정렬: [Tool('수준계',3.5), Tool('해머', 1.25), Tool('스크류드라이버',0.5), Tool('끝',0.25)]
tools.sort(key=lambda x: x.name)
print('\n정렬:', tools) # 정렬: [Tool('끝',0.25), Tool('수준계',3.5), Tool('스크류드라이버',0.5), Tool('해머', 1.25)]
*예시2: weight로 정렬하는 람다 함수 만들어서 sort의 key 파라미터 전달
tools.sort(key=lambda x:x.weight)
print('무게 순 정렬:', tools)
# 무게 순 정렬: [Tool('끝',0.25),Tool('스크류드라이버',0.5), Tool('해머', 1.25),Tool('수준계',3.5)]
*예시3: lower메서드 사용하여 장소 이름 소문자화 후 알파벳 순으로 비교
places = ['home', 'work', 'New York', 'Paris']
places.sort()
print('대소문자 구분:', places) #대소문자 구분: ['New York', 'Paris', 'home', 'work']
places.sort(key=lambda x:x.lower)
print('대소문자 무시:', places)#대소문자 무시: ['home', 'New York', 'Paris', 'work']
*예시4: tuple타입을 사용하여 weight 먼저 정렬 후 name으로 정렬
튜플은 임의의 파이썬 값을 넣는 불변의 값이다.
비교 가능하며 자연스러운 순서가 정해져있다.
특별 비교 메서드는 튜플의 각 위치를 이터레이션하면서 각 인덱스에 해당하는 원소를 한 번에 하나씩 비교방식 구현
비교하는 두 튜플의 첫 번째 위치에 있는 값이 서로 같으면 튜플의 비교 메서드는 두 번째 위치에 있는 값과 서로 비교
두 번째 위치도 같으면 세 번째 이우 위치 등에도 비교 반복
power_tools = [
Tool('드릴', 4),
Tool('원형 톱', 5),
Tool('착암기', 40),
Tool('연마기', 4),
]
saw = (5, '원형 톱')
jackhammer = (40, '착암기')
assert not (jackhammer < saw) #예상대로 결과 나온다
drill = (4, '드릴')
sander = (4, '연마기')
assert drill[0] == sander[0] #무게가 같다
assert drill[1] < sander[1] #알파벳 순으로 볼 때 더 작다
assert drill < sander #그러므로 드릴 먼저
power_tools.sort(key=lambda x: (x.weigh, x.name))
print(power_tools) #[Tool('드릴', 4),Tool('연마기', 4),Tool('원형 톱', 5),Tool('착암기', 40)]
*예시5: 단항 부호 반전(-) 연산자를 사용해서 정렬 방향을 혼합하여 정렬 순서는 그대로 둔 채 반전된 값의 정렬 순서를 바꾼다.
weight기준으로 내림차순 정렬 후 name기준으로 오름차순 정렬
모든 타입에 부호 반전이 가능한 것은 아니다.
power_tools.sort(key=lambda x: (-x.weight, x.name))
print(power_tools)
#[Tool('착암기', 40) , Tool('원형 톱', 5),Tool('드릴', 4), Tool('연마기'', 4)]
*안정적인 정렬 알고리즘
리스트 타입의 sort메서드는 key함수가 반환하는 값이 같을 경우 원래 순서 그대로 유지
리스트에 대해 서로 다른 기준으로 sort를 여러 번 호출
weight기준 내림차순, name기준 오름차순으로 정렬 (sort 두 번 호출 방식)
power_tools.sort(key =lambda x:x.name) #name기준 오름차순
power_tools.sort(key=lambda x:x.weight,
reverse=True) # weight 기준 내림차순
print(power_tools)
#[Tool('착암기', 40) , Tool('원형 톱', 5),Tool('드릴', 4), Tool('연마기'', 4)]
key함수를 사용해 tuple을 반환하게 하고 단항 부호로 반전 연산을 활용하는 접근 방식이 코드가 적고 읽기 쉽다.
꼭 필요할 때만 sort를 여러 번 호출하는 방법 사용 권장한다.
리스트 타입에 들어 있는 sort메서드를 사용하면 자연스러운 순서로 리스트의 원소 정렬한다.
원소타입에 특별 메소드를 지정하지 않으면 sort메서드 사용 불가하다
sort메서드의 key파라미터를 사용하면 리스트의 각 원소 대신 비교에 사용할 객체를 반환하는 도우미 함수 제공한다.
key함수에서 튜플을 반환하면 여러 정렬 기준을 하나로 엮을 수 있다
부호를 바꿀 수 없는 타입의 경우 여러 정렬 기준을 조합하여 각 정렬 기준마다 reverse 값으로 정렬 순서를 지정하면서 sort메서드 여러 번 사용