티스토리 뷰

[문제]

다음은 a~j까지 열명의 학생의 점수(50~100사이 랜덤)과 그 학생의 점수합계, 그리고 전체 점수합의 평균과 이 학생의 점수합의 차이를 보여준다. 이 예에서 평균은 220.1이고 a 학생은 점수합이 평균과 18.1 차이임을 보여준다.

a [59, 81, 62] => 202 (-18.1)
b [96, 70, 94] => 260 (+39.9)
c [74, 92, 93] => 259 (+38.9)
d [53, 75, 52] => 180 (-40.1)
e [75, 67, 75] => 217 ( -3.1)
f [58, 55, 74] => 187 (-33.1)
g [54, 73, 83] => 210 (-10.1)
h [58, 50, 89] => 197 (-23.1)
i [79, 96, 93] => 268 (+47.9)
j [57, 96, 68] => 221 ( +0.9)

[해결방법]

이 문제는 몇 단계로 데이터를 만들어야 하는 문제이다.

  1. 먼저 학생 이름과 학생별 점수를 만들어야 한다. 이 때 이름은 a-j이고 점수는 학생마다 세 개인데 50~100 사이의 값으로 랜덤하게 만들어야 한다.
  2. 두 번째로 각 학생의 점수합을 구해야 하고 전체 점수합의 평균을 구해야 한다.
  3. 마지막으로 각 학생의 점수합이 점수합 평균과 차이를 구해야 한다.
  4. 이렇게 구한 값을 형식에 맞게 보기 좋게 출력해야 한다.

[자료구조]

자료구조는 어떻게 하는 것이 좋을까?

열명의 학생에 대해 이름과 점수 세개, 합계가 필요하다. 이것을 각각 따로 리스트를 만들어서 zip을 통해 하나의 리스트로 만들 수 있다. 점수 세개는 그냥 하나의 리스트에 만들어도 될 것이다. 즉 한 학생의 기본 정보는 다음과 같은 구조를 가질 것이다.

['a', [59, 81, 62]]

점수 합계는 두 번째 리스트를 sum([59, 81, 62]) 함수를 이용해 구할 수 있다.

(1) 데이터 만들기

학생의 이름과 점수 세개를 가진 리스트를 만드는 방법은 여러 가지가 있다.

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([alpha[i], one])

위의 방법은 학생들의 이름과 점수 세개를 하나씩 append하는 방법이다.

이것을 좀더 보기좋계 zip을 이용해보면 다음과 같은 코드가 된다.

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))

zip은 스트링이나 리스트같은 연속된 자료구조의 데이터를 여러 개 매개변수로 받아서 그것들을 순서대로 한개씩 묶어서 돌려주는 제너레이터다. zip으로 얻어진 결과는 for 루프에서 한번만 사용가능하므로(재사용 불가) 여러 번 사용하고 정렬도 하는 등의 방식으로 사용하려면 제너레이터가 아니라 리스트여야 한다. 그래서 list(zip(...))으로 해서 리스트를 생성했다.

여기까지 하면 학생의 정보는 다음과 같은 구조의 ziplist에 들어가 있다. (랜덤값 생성이므로 문제의 값과 달라진다.)

('a', [60, 91, 81], 232)
('b', [67, 84, 75], 226)
('c', [98, 84, 63], 245)
('d', [92, 80, 54], 226)
('e', [57, 86, 52], 195)
('f', [93, 65, 57], 215)
('g', [52, 96, 71], 219)
('h', [65, 90, 88], 243)
('i', [63, 65, 84], 212)
('j', [91, 64, 94], 249)
>>> 

위의 코드에서 하는 생성 단계를 컴프리헨션으로 바꾸어보면 다음과 같다. (컴프리헨션은 리스트 for 루프를 좀 간결하게 표현해 주는 역할을 한다)

import random

alpha = 'abcdefghij'
scores = [[random.randint(50, 100), 
		random.randint(50, 100), 
		random.randint(50, 100)] for _ in range(10)]
sums = [sum(x) for x in scores]
ziplist = list(zip(alpha, scores, sums))

(2) 점수 합계의 평균과의 차이와 전체 데이터 출력하기

전체 점수 합계의 평균을 구하고 각 학생의 점수 합계와 평균과의 차이를 출력해 준다.

평균을 구하기 위해서는 위에서 만들어놓은 점수합 리스트 sums가 유용하게 쓰인다. 합계 구하는 sum() 함수와 길이 구하는 len() 함수를 쓸 수 있다.

avg = sum(sums) / len(sums)

그럼 학생별 데이터와 평균을 가지고 우리가 원하는 형태의 출력을 해야 한다. 한 학생에 대해 출력되어야 할 정보는 다음과 같은 형식을 가진다.

# 데이터 형식, 튜플의 리스트
('a', [59, 81, 62], 202)
# 출력 형식
a [59, 81, 62] => 202 (-18.1)

이렇게 형식에 맞게 출력하기 위해서 format 문을 이용해야 한다.

for x in ziplist:
    print(x)
    print('{} {} => {} ({})'.format(x[0], x[1], x[2], x[2]-avg))

이렇게 출력한 결과는 다음과 같다.

a [72, 96, 57] => 225 (-6.800000000000011)
b [98, 91, 59] => 248 (16.19999999999999)
c [95, 81, 54] => 230 (-1.8000000000000114)
d [90, 88, 50] => 228 (-3.8000000000000114)
e [88, 70, 83] => 241 (9.199999999999989)
f [72, 90, 71] => 233 (1.1999999999999886)
g [90, 65, 98] => 253 (21.19999999999999)
h [62, 86, 74] => 222 (-9.800000000000011)
i [89, 86, 96] => 271 (39.19999999999999)
j [53, 53, 61] => 167 (-64.80000000000001)

그런데 위의 출력은 자리수나 정렬이 보기좋게 되지가 않는다. 특히 마지막 괄호 속에 있는 평균과의 차이에 여러 가지 문제가 있다.

  • 부호를 -만 붙였는데 양수도 + 부호를 붙여야 한다.
  • 소수점 이하 두 자리까지만 보여야 한다.
  • 소수점 위가 한자리와 두자리가 섞여있는데 자리수를 맞추어야 한다.

위와 같이 출력하기 위해서는 format을 이용하여 다음과 같이 작성해 볼 수 있다.

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

그럼 이제 출력이 보기좋게 줄맞추어 나오게 된다. {:+6.2f}는 +는 부호를 붙여라, 6은 전체 소수점수의 자리수를 여섯 자리로 하고, 소수점 이하는 두자리로 하라는 뜻이다.

a [69, 88, 96] => 253 (+13.60)
b [75, 67, 83] => 225 (-14.40)
c [77, 96, 63] => 236 ( -3.40)
d [79, 86, 80] => 245 ( +5.60)
e [64, 96, 78] => 238 ( -1.40)
f [65, 78, 59] => 202 (-37.40)
g [88, 59, 93] => 240 ( +0.60)
h [97, 98, 85] => 280 (+40.60)
i [96, 79, 59] => 234 ( -5.40)
j [89, 81, 71] => 241 ( +1.60)

한 가지 더 추가해 보면 차이값이 한자리와 두자리가 섞여서 부호가 들쑥날쑥하니까 그것을 개선하기 위해 {:+06.2f}로 고칠 수 있다. 즉 +는 부호를 붙여라, 06은 여섯 자리로 하되 앞에 0을 채워라, 소수점 이하는 두자리로 해라 이런 뜻이 된다.

a [69, 88, 96] => 253 (+13.60)
b [75, 67, 83] => 225 (-14.40)
c [77, 96, 63] => 236 (-03.40)
d [79, 86, 80] => 245 (+05.60)
e [64, 96, 78] => 238 (-01.40)
f [65, 78, 59] => 202 (-37.40)
g [88, 59, 93] => 240 (+00.60)
h [97, 98, 85] => 280 (+40.60)
i [96, 79, 59] => 234 (-05.40)
j [89, 81, 71] => 241 (+01.60)
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
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
글 보관함