티스토리 뷰

앞의 글에서 만들었던 학생 점수 데이터를 이용하여 다양한 기준으로 정렬하는 방법을 살펴보겠습니다.

우리는 지금 한 학생의 여러 개 정보를 zip을 이용해 묶어 출력하고 있습니다. zip을 하면 얻어진 결과는 리스트가 아니고 generator 값입니다. (제너레이터는 요청될 때 차례로 하나씩 계산하는 함수 또는 수식이고 리스트를 모든 값을 다 계산해서 저장해둔 형태가 됩니다. 이 차이에 대해서는 제너레이터 포스트를 참고하세요. )

정렬을 하려면 모든 데이터가 리스트에 들어있어야 하므로 우리는 zip으로 여러 개 리스트를 묶은 결과를 다시 list를 통해 바꾸어 주어야 합니다.

ziplist = list(zip(alpha, scores, sums))

이것은 사실 튜플(이름, 점수들, 합계)의 리스트가 되는데, 이 리스트를 sort() 함수를 이용해 정렬하면 첫번째 요소에 대해 정렬하게 됩니다. 

import random
alpha = 'abcdefghij'
scores = []
for i in range(10):
    one = [random.randint(50, 100), 
		random.randint(50, 100), 
		random.randint(50, 100)]
    scores.append(one)
sums = []
for x in scores:
	sums.append(sum(x))
ziplist = list(zip(alpha, scores, sums))
ziplist.sort()
for x in ziplist:
    print(x)

첫번째 요소인 이름은 a ~ z까지 차례로 이미 정렬되어 있으므로 리스트에 아무런 변동이 없게 되겠지요? 결과는 다음과 같습니다.

('a', [53, 80, 60], 193)
('b', [74, 64, 96], 234)
('c', [51, 69, 56], 176)
('d', [93, 67, 82], 242)
('e', [86, 51, 61], 198)
('f', [85, 85, 79], 249)
('g', [70, 59, 66], 195)
('h', [71, 97, 89], 257)
('i', [54, 64, 73], 191)
('j', [87, 52, 59], 198)

리스트나 튜플을 요소로 가지는 리스트에서 정렬은 두 개의 리스트나 튜플을 비교하는 연산을 이용합니다. 즉 위에서 ('a', [69, 88, 96], 253) < ('b', [75, 67, 83], 225) 라는 관계를 이용해서 정렬합니다. 두 튜플의 비교는 첫번째 요소를 비교하고 같으면 그 다음 요소를 비교하는 식입니다. 그럼 위의 리스트를 점수합계로 정렬하려면 어떻게 할 수 있을까요? 각 요소에 점수 합계가 제일 앞에 오게 바꾸어야 합니다. 그럼 정렬은 첫번째 요소인 점수 합계로 비교하게 됩니다.

ziplist2 = list(zip(sums, alpha, scores))
ziplist2.sort()
for x in ziplist2:
    print('{} {} => {:3d} ({:+06.2f})'.format(x[1], x[2], x[0], x[0]-avg))

위의 ziplits2는 합계가 제일 앞에 오게 zip 함수를 적용했습니다. 그러므로 학생 별로 합계, 이름, 점수 순으로 데이터를 가지고 있겠지요? 이것을 sort() 하면 합계 점수가 제일 작은 것이 제일 앞에 오게 됩니다. 출력할 때 값을 보여주는 순서를 조정해 주어야 되겠지요? (합계, 이름, 점수) 순서입니다.

c [51, 69, 56] => 176 (-37.30)
i [54, 64, 73] => 191 (-22.30)
a [53, 80, 60] => 193 (-20.30)
g [70, 59, 66] => 195 (-18.30)
e [86, 51, 61] => 198 (-15.30)
j [87, 52, 59] => 198 (-15.30)
b [74, 64, 96] => 234 (+20.70)
d [93, 67, 82] => 242 (+28.70)
f [85, 85, 79] => 249 (+35.70)
h [71, 97, 89] => 257 (+43.70)

만약 점수 세 개 중에 첫번째 것(국영수 중 국어점수라고 해 보죠)으로 정렬을 하고 싶다면 어떻게 해야 할까요?

정렬하고 싶은 기준값을 리스트의 제일 앞에 두어야 합니다. 그러기 위해서는 국어 점수가 제일 앞에 오게 순서를 조정해 주어야 합니다. 국영수 점수 리스트는 그대로 두고 국어만 제일 앞에 추가하는 방법은 다음과 같습니다.

korscores = [x[0] for x in scores]  			# 국어 점수의 리스트를 따로 만든다
ziplist3 = list(zip(korscores, alpha, scores, sum))	# 그것을 제일 앞에 넣고 zip
ziplist3.sort()  					# 국어 점수 기준으로 정렬
for x in ziplist2:
    print('{} {} => {:3d} ({:+06.2f})'.format(x[1], x[2], x[3], x[3]-avg))

국어 점수를 기준으로 출력한 결과는 다음과 같습니다. (랜덤 생성이어서 점수 값이 실행할 때마다 달라집니다.)

j [55, 60, 96] => 211 (-11.30)
c [60, 94, 70] => 224 (+01.70)
b [66, 52, 67] => 185 (-37.30)
e [68, 74, 69] => 211 (-11.30)
f [70, 95, 87] => 252 (+29.70)
a [82, 80, 57] => 219 (-03.30)
h [82, 50, 77] => 209 (-13.30)
g [89, 92, 84] => 265 (+42.70)
d [92, 80, 56] => 228 (+05.70)
i [94, 52, 73] => 219 (-03.30)

sort() 메소드는 오름차순 정렬을 하는데 이것을 내림차순으로 바꾸는 방법은 두 가지가 있습니다.

ziplist3.reverse()
for x in ziplist3:
    print('{} {} => {:3d} ({:+06.2f})'.format(x[1], x[2], x[3], x[3]-avg))

오름차순으로 정렬된 리스트를 reverse() 메소드로 뒤집었습니다. 그러면 국어 점수가 제일 큰 것부터 내림차순으로 출력됩니다.

i [94, 52, 73] => 219 (-03.30)
d [92, 80, 56] => 228 (+05.70)
g [89, 92, 84] => 265 (+42.70)
h [82, 50, 77] => 209 (-13.30)
a [82, 80, 57] => 219 (-03.30)
f [70, 95, 87] => 252 (+29.70)
e [68, 74, 69] => 211 (-11.30)
b [66, 52, 67] => 185 (-37.30)
c [60, 94, 70] => 224 (+01.70)
j [55, 60, 96] => 211 (-11.30)

또 한가지 방법은 sort() 메소드에서 매개변수를 reverse=True로 주는 방법입니다. 그러면 정렬이 내림차순으로 얻어지게 됩니다.

ziplist3.sort(reverse=True)

사실 sort의 놀라운 기능 중 하나는 key 매개변수의 사용법입니다. 이것은 함수를 이용하는 방법인데, 다음과 같은 코드로 우리는 국어 점수를 기준으로 정렬하게 할 수가 있습니다.

def takeKor(elem):
	return elem[1][0]

ziplist = list(zip(alpha, scores, sums))
ziplist2 = sorted(ziplist,key=takeKor)

정렬 기준을 줄 수 있다면 우리는 굳이 리스트를 새로 만들 필요가 없습니다. ziplist에 있던 데이터를 정렬하여 ziplist2로 저장하면 됩니다. 이런 일을 해주는 함수가 sorted입니다. 원래 리스트 ziplist는 그대로 두고 정렬된 결과를 다른 리스트로 반환해 줍니다. 그것을 ziplist2에 저장하였습니다.

여기서 takeKor 함수는 리스트의 요소 하나를 받아서 국어 점수를 돌려주는 함수입니다. 그러면 sort 함수에서는 key 매개변수에 그 함수를 넣어서 국어점수를 키로 정렬하게 할 수 있습니다.

매번 키에 해당하는 요소를 반환하는 함수를 만들려면 번거로운 일입니다. 이런 식으로 한번 쓰일 함수를 굳이 def 하지 않고 만들 수 있게 해주는 것이 람다의 기능입니다. 이 예제의 정렬 문제는 한걸음 더 나아가면 람다 함수를 이용할 수 있습니다. 그러면 다음과 같이 다양한 키를 이용하여 정렬하는 것이 한줄 코드로 가능해 지게 됩니다. 

ziplist2 = sorted(ziplist,key=lambda x:x[2])		# 합계를 키로 정렬

ziplist3 = sorted(ziplist,key=lambda x:x[1][0])		# 국어 점수를 키로 정렬

# 국어 점수를 키로 내림차순 정렬
ziplist3 = sorted(ziplist,key=lambda x:x[1][0], reverse=True)	

람다에 대해서는 별도의 포스트에서 자세하게 다룰 예정입니다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함