[Python] .sort(), sorted(), 다중 조건
파이썬에서,
리스트를 정렬할 때 사용하는 sort함수와 sorted함수의 차이점 에 대해서 자세히 알아보자.
.sort() vs sorted()
.sort
함수는 리스트명.sort() 형식으로 "리스트형의 메서드"이며 리스트 원본 값을 직접 변경.sorted
함수는 sorted(리스트명) 형식으로 "내장 함수"이며 리스트 원본 값은 그대로 두고정렬된 값을 반환한다.
.sort()
.sort()
는 기본적으로 오름차순을 기본 값으로 가진다.list.sort()
함수의 리턴 값은 존재하지 않아서 출력하게 되면None
이 출력 된다.list
자체의 값을 바꿔주고list
의 메서드 이다.
>>> a=[3,5,2,2,4,1,10,9]
>>> b=a.sort()
>>> print(a)
[1, 2, 2, 3, 4, 5, 9, 10]
>>> print(b)
None
sorted()
- 기본적으로 오름차순이 기본 값이다.
- 인자로 문자열, 튜플, 딕셔너리, 제너레이터 등 반복 가능한 객체를 정렬하여 반환한다.
- 원본 리스트의 값은 유지 되고, 함수의 리턴 값으로 정렬된 리스트가 반환된다.
>>> a=[3,5,2,2,4,1,10,9]
>>> b=sorted(a)
>>> print(a)
[3, 5, 2, 2, 4, 1, 10, 9]
>>> print(b)
[1, 2, 2, 3, 4, 5, 9, 10]
Key Functions
- 둘 다
key
인자를 가지고 있고, 비교하는 기준으로 사용한다. - 인자 없이 그냥
sorted()
만 쓰면, 리스트 아이템의 각 요소를 순서대로 정렬한다.
>>> a = [(1, 2),(0, 1),(5, 1),(-1,1),(5, 2),(3,4),(3, 0)]
>>> sorted(a)
[(-1, 1), (0, 1), (1, 2), (3, 0), (3, 4), (5, 1), (5, 2)]
key
인자에 함수를 넘겨주면 해당 함수의 반환 값을 비교하여 순서대로 정렬한다.key
인자로 전달된 함수는 입력 아이템마다 한번 씩 호출되어진다.
>>> sorted(a, key = lambda x : x[0])
[(-1, 1), (0, 1), (1, 2), (3, 4), (3, 0), (5, 1), (5, 2)]
>>> sorted(a, key = lambda x : x[1])
[(3, 0), (0, 1), (5, 1), (-1, 1), (1, 2), (5, 2), (3, 4)]
아이템의 첫 번째 인자를 기준으로 내림차순으로 먼저 정렬하고,
두 번째 인자를 기준으로 오름차순으로 정렬하게 하려면, 다음과 같이 사용한다.
비교할 아이템의 요소가 복수 개일 경우, 튜플로 그 순서를 내보내주면 된다.
- ex.
sorted(e, key = lambda x : (-x[0], x[1]))
-
를 붙이면, 현재 정렬 차순과 반대로 하게 된다
- ex.
>>> sorted(a,key=lambda x: (-x[0],x[1]))
[(5, 1), (5, 2), (3, 0), (3, 4), (1, 2), (0, 1), (-1, 1)]
- 일반적인 패턴은 클래스나 복잡한 객체들을 정렬할 때 사용한다.
>>> student_objects=[
... Student('bro','A',20),
... Student('grammer','B',12),
... Student('james','C',18),
... Student('linda','B',18),
...]
>>>sorted(student_objects,key=lambda student: student.age)
[('grammer', 'B', 12), ('james', 'C', 18), ('linda', 'B', 18), ('bro', 'A', 20)]
Operator Module Functions
- 파이썬에서 더 편리하게 사용할 수 있는 접근자 함수를 제공한다.
- operator모듈의
itemgetter()
,attrgetter()
- 인덱스로 가지고 오는 변수는
itemgetter()
함수 사용, 객체의 속성을 가지고 오는 함수는attrgetter()
사용 - 하나 뿐만 아니라 여러 개의 값을 가지고 비교 할 수 있다.
>>> student_tuples=[
... ('bro','A',20),
... ('grammer','B',12),
... ('james','C',18),
... ('linda','B',18),
... ]
>>> from operator import itemgetter, attrgetter
>>> sorted(student_tuples, key=itemgetter(0)) # lambda x: x[0]과 같은 정렬.
[('bro', 'A', 20), ('grammer', 'B', 12), ('james', 'C', 18), ('linda', 'B', 18)]
>>> sorted(student_objects, key=attrgetter('age')) #lambda student: student.age와 같음.
[('grammer', 'B', 12), ('james', 'C', 18), ('linda', 'B', 18), ('bro', 'A', 20)]
>>> sorted(student_tuples, key=itemgetter(1,2))
[('bro', 'A', 20), ('grammer', 'B', 12), ('linda', 'B', 18), ('james', 'C', 18)]
>>> sorted(student_objects, key=attrgetter('grade', 'age'))
[('bro', 'A', 20), ('grammer', 'B', 12), ('linda', 'B', 18), ('james', 'C', 18)]
Sort Stability
- 정렬은 stable sort를 하게 된다.
- stable sort: 키의 우선순위가 같을 때 기존 list의 순서를 보존한다.
- unstable sort: 키의 우선순위가 같을 때 기존 list의 순서를 보존하지 않는다.
>>> tmp = [(21,'Junkyu'),(21,'Dohyun'),(20,'Sunyoung')]
>>> sorted(tmp,key= lambda x: x[0])
[(20, 'Sunyoung'), (21, 'Junkyu'), (21, 'Dohyun')]
코드를 보면
x[0]
를 통해서 키 값을 지정하고 21이라는 같은 키 값을 가지는튜플
(21,'Junkyu'),(21,'Dohyun')
가 존재하는데 이 값의 순서가 정렬 후에도 보존이 된다.파이썬에서는 내부적으로 Hybrid Algorithm중 하나인 Timsort알고리즘을 사용하고 있고 이 알고리즘은 데이터 셋 내 이미 존재하는 순서를 이용하는 이점을 가지고 있다.
덧붙여 말하자면 이게 당연하다고 생각할 수 있지만 내장 함수로 Stable sort를 지원 안 하는 언어도 있고, 쓰는 정렬 알고리즘에 따라서 키 값의 우선순위가 같다면 아이템들의 순서는 랜덤하게 배정 받게 된다.
Reference
- http://blog.weirdx.io/post/50236