2023. 9. 14. 16:40ㆍ파이썬(Python)
1. 우선순위 객체 정렬
1-1. 클래스를 이용한 객체 정렬
- 학생들의 국어, 수학, 영어 점수가 있을 때, 수학 점수를 기준으로 오름차순으로 정렬한다.
- 만약 수학 점수가 같다면, 국어 점수를 기준으로 오름차순으로 정렬한다.
- 이처럼 우선순위를 갖는 경우에는 lambda 함수의 반환값을 tuple 값으로 정의해준다.
print((3,5)>(2,8))
print((3,5)>(3,7))
print((3,5)>(4,2))
True
False
False
- 위와 같이 tuple끼리 비교하면 첫 번째 값을 기준으로 먼저 비교한다.
- 첫 번째 값이 동일하다면 두 번째 값을 기준으로 비교를 한다.
- 값이 2개뿐만 아니라 여러 개일 때도 마찬가지이다.
class Student:
def __init__(self, kor, math, eng):
self.kor = kor
self.math = math
self.eng = eng
n=int(input())
student_point=[]
for _ in range(n):
kor,math,eng=tuple(map(int,input().split()))
student_point.append(Student(kor,math,eng))
student_point.sort(key=lambda x:(x.math,x.eng))
for point in student_point:
print(point.kor, point.math, point.eng)
>> 5
>> 20 50 60
>> 80 70 50
>> 30 50 90
>> 50 80 30
>> 70 50 90
# 국어, 수학, 영어 점수
20 50 60
30 50 90
70 50 90
80 70 50
50 80 30
- 수학 점수를 기준으로 오름차순을 한 후, 수학 점수가 같으면 영어 점수를 기준으로 오름차순으로 정렬한다.
- 영어 점수까지 같으면 우선순위 조건에 없는 값으로 오름차순으로 정렬한다. (index가 작은 값부터 오름차순 정렬)
- 만약 수학 점수가 같으면 국어 점수를 기준으로 내림차순으로 정렬하는 방법은 다음과 같다.
class Student:
def __init__(self, kor, math, eng):
self.kor = kor
self.math = math
self.eng = eng
n=int(input())
student_point=[]
for _ in range(n):
kor,math,eng=tuple(map(int,input().split()))
student_point.append(Student(kor,math,eng))
student_point.sort(key=lambda x:(x.math, -x.kor))
for point in student_point:
print(point.kor, point.math, point.eng)
>> 5
>> 20 50 60
>> 80 70 50
>> 30 50 90
>> 50 80 30
>> 70 50 90
# 국어, 수학, 영어 점수
70 50 90
30 50 90
20 50 60
80 70 50
50 80 30
- 국어 점수를 기준으로 내림차순을 한다면 -x.kor을 하면 된다.
1-2. 튜플을 이용한 객체 정렬
- lambda 함수의 반환 값으로 tuple을 사용한다.
- 우선순위는 영어, 국어, 수학 점수이고 모두 내림차순으로 정렬하는 코드는 다음과 같다.
n=int(input())
student_points=[tuple(map(int,input().split())) for _ in range(n)]
student_points.sort(key=lambda x: (-x[2],-x[0], -x[1]))
for kor, math, eng in student_points:
print(kor, math, eng)
>> 5
>> 20 50 60
>> 80 70 50
>> 50 50 90
>> 50 80 30
>> 70 50 90
# 국어, 수학, 영어 점수
70 50 90
50 50 90
20 50 60
80 70 50
50 80 30
2. 다양한 조건의 객체 정렬
2-1. 클래스를 이용한 객체 정렬
- 국어, 수학, 영어 점수를 가진 학생들의 정보를 점수의 합을 기준으로 내림차순으로 정렬한다.
- 이처럼 정렬 기준이 멤버 변수가 아니라면, lambda 함수에 기준 값을 반환해 주도록 설정한다.
class Student:
def __init__(self, kor, math, eng):
self.kor=kor
self.math=math
self.eng=eng
student_points=[]
n=int(input())
for _ in range(n):
kor,math,eng=map(int,input().split())
student_points.append(Student(kor,math,eng))
student_points.sort(key=lambda x:-(x.kor+x.math+x.eng))
for point in student_points:
print(point.kor, point.math, point.eng, point.kor+point.math+point.eng)
>> 5
>> 20 50 60
>> 80 70 50
>> 50 50 90
>> 50 80 30
>> 70 50 90
# 국어, 수학, 영어, 총점
70 50 90 210
80 70 50 200
50 50 90 190
50 80 30 160
20 50 60 130
2-2. 튜플을 이용한 객체 정렬
n=int(input())
student_points=[tuple(map(int,input().split())) for _ in range(n)]
student_points.sort(key=lambda x:-(x[0]+x[1]+x[2]))
for kor,math,eng in student_points:
print(kor,math,eng,kor+math+eng)
>> 5
>> 20 50 60
>> 80 70 50
>> 50 50 90
>> 50 80 30
>> 70 50 90
# 국어, 수학, 영어, 총점
70 50 90 210
80 70 50 200
50 50 90 190
50 80 30 160
20 50 60 130
2-3. cmp_to_key 함수 사용
- lambda로 처리하기 어려운 경우에는 cmp_to_key 함수를 사용한다.
- functools 내에서 cmp_to_key를 import 한다.
- compare라는 비교하는 함수를 만들어서 cmp_to_key(compare) 식으로 사용한다.
■ compare 함수
- compare 함수에는 인자를 2개 설정한다. (이를 x, y라 하겠다.)
- x가 앞에 있는 원소, y가 뒤에 있는 원소이다.
- 정렬 기준은 3가지가 있고 이에 대한 반환값은 다음과 같다.
1. 조건에 부합하는 순서라면 음수
2. 조건과 반대되는 순서라면 양수
3. 우선순위가 같으면 0
- 만약 compare(x, y)를 하여 양수가 반환되면 x와 y 순서를 바꾼다.
Q) 점수 Custom 정렬
- 학생들은 국어, 수학, 영어 점수를 가지고 있다.
- 정렬 기준은 다음과 같다.
- 국어 점수와 수학 점수를 더한 값이 3의 배수인 학생 점수를 제일 우선순위로 둔다.
- 그중 국어와 수학 점수의 합이 더 높은 사람을 우선으로 한다.
- 국어와 수학 점수의 합이 3의 배수가 아니면 수학과 영어 점수의 합이 큰 사람을 우선순위로 둔다.
from functools import cmp_to_key
n=int(input())
student_points=[tuple(map(int,input().split())) for _ in range(n)]
def compare_two_points(x,y,a,b):
if x[a]+x[b]<y[a]+y[b]:
return 1
elif x[a]+x[b]>y[a]+y[b]:
return -1
else:
return 0
def compare(x,y):
if (x[0]+x[1])%3==0 and (y[0]+y[1])%3!=0:
return -1
elif (y[0]+y[1])%3==0 and (x[0]+x[1])%3!=0:
return 1
else:
if (x[0]+x[1])%3==0 and (y[0]+y[1])%3==0:
return compare_two_points(x,y,0,1)
elif (x[0]+x[1])%3!=0 and (y[0]+y[1])%3!=0:
return compare_two_points(x,y,1,2)
student_points.sort(key=cmp_to_key(compare))
for kor,math,eng in student_points:
print(kor,math,eng)
>> 5
>> 40 50 60 # 학생 1
>> 80 70 50 # 학생 2
>> 50 50 90 # 학생 3
>> 50 80 30 # 학생 4
>> 70 50 90 # 학생 5
80 70 50
70 50 90
40 50 60
50 50 90
50 80 30
- 학생 1과 학생 2를 비교하면 국어와 수학의 합이 각각 40+50=90, 80+70=150 이므로 학생 2가 앞에 와야 한다.
- 학생 4와 학생 5를 비교하면 국어와 수학의 합이 각각 50+80=130, 70+50=120이고 학생 5의 합인 120이 3의 배수이므로 학생 4보다 앞에 와야 한다.
- 학생 3과 학생 4를 비교하면 국어와 수학의 합이 각각 50+50=100, 50+80=130 이므로 두 학생 모두 3의 배수가 아니다.
- 학생 3과 학생 4는 수학과 영어의 합이 각각 50+90=140, 80+30=110 이므로 학생 3이 학생 4보다 먼저 와야 한다.
- 현재 학생들의 점수는 튜플 값으로 되어 있어 0, 1, 2번째 index는 각각 국어, 수학, 영어 점수이다.
- compare 함수는 다음과 같다.
- 두 학생의 점수 x, y에서 x가 y보다 앞에 있다.
- x의 국어와 수학의 합이 3의 배수이고 y의 국어와 수학의 합이 3의 배수가 아니면 x가 y보다 먼저 와야 하므로 음수 (-1)을 반환한다.
- x의 국어와 수학의 합이 3의 배수가 아니고 y의 국어와 수학의 합이 3의 배수이면 y가 x보다 먼저 와야 하므로 양수 (1)을 반환한다.
- 위 두 조건이 아니면 compare_two_points를 수행하는데 다음과 같다.
- x, y는 각각 학생의 점수이고 a, b는 x 또는 y의 index이다.
- x, y의 국어와 수학의 합이 3의 배수이면 국어와 수학의 합이 더 큰 사람이 먼저 와야 하므로 compare_two_points의 a, b는 각각 0, 1이 되어 반환한다.
- x, y의 국어와 수학의 합이 3의 배수가 아니면 수학과 영어의 합이 더 큰 사람이 먼저 와야 하므로 compare_two_points의 a, b는 각각 1, 2가 되어 반환한다.
- sort를 할 때 lambda 대신 cmp_to_key를 사용하고 조건에 만족하는 함수 compare를 인자값으로 사용한다.
'파이썬(Python)' 카테고리의 다른 글
[Python] 시간과 날짜, 요일 구하기 (0) | 2023.10.20 |
---|---|
[Python] - 객체 정렬, 등수 표현, 객체 정렬 문제 풀이 (정보 정렬, 좌표 거리, 정렬된 위치 탐색) (0) | 2023.09.22 |
[Python] 객체 정렬 - 클래스, 튜플 객체 정렬. lambda. 오름차순. 내림차순. 문자열 사전순 (0) | 2023.02.11 |
[Python] 클래스 대신 튜플(Tuple) 사용하기 (0) | 2023.02.07 |
[Python] 클래스(Class) - 클래스 정의, 정보 저장, 값 변경, 객체 리스트 (0) | 2023.02.05 |