[Python 100일 챌린지] Day 18 - 리스트 컴프리헨션
5줄 짜리 for문을 단 1줄로! Python에서 가장 우아하고 강력한 리스트 생성 방법인 리스트 컴프리헨션을 마스터해봅시다. 코드를 더 짧고 읽기 쉽게 만들어주는 Pythonic한 방법으로, 실무에서 가장 많이 사용되는 필수 문법입니다. (23분 완독 ⭐⭐)
🎯 오늘의 학습 목표
📚 사전 지식
🎯 학습 목표 1: 리스트 컴프리헨션이 무엇인지 이해하기
리스트 컴프리헨션이란?
리스트 컴프리헨션 = 리스트를 간결하게 생성하는 Pythonic한 방법
반복문과 조건문을 하나의 표현식으로 결합하여 리스트를 생성하는 Python의 강력한 기능입니다.
1
2
3
4
5
6
7
8
9
# 일반적인 방법 (5줄)
numbers = []
for i in range(5):
numbers.append(i * 2)
print(numbers) # [0, 2, 4, 6, 8]
# 리스트 컴프리헨션 (1줄!)
numbers = [i * 2 for i in range(5)]
print(numbers) # [0, 2, 4, 6, 8]
왜 리스트 컴프리헨션을 사용할까?
3가지 핵심 이유
| 장점 | 설명 | 예시 |
|---|---|---|
| 간결성 | 여러 줄을 한 줄로 압축 | 5줄 → 1줄 |
| 가독성 | 의도가 명확하게 드러남 | “각 요소를 제곱한다” |
| 성능 | 일반 반복문보다 빠름 | 약 30-40% 빠름 |
전통적 방법 vs 컴프리헨션
예제 1: 제곱수 리스트 만들기
1
2
3
4
5
6
7
8
9
10
# ❌ 전통적 방법 (5줄)
squares = []
for i in range(1, 6):
square = i ** 2
squares.append(square)
print(squares) # [1, 4, 9, 16, 25]
# ✅ 리스트 컴프리헨션 (1줄)
squares = [i ** 2 for i in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
예제 2: 문자열 리스트 변환
1
2
3
4
5
6
7
8
9
10
# ❌ 전통적 방법 (4줄)
fruits = ["apple", "banana", "grape"]
upper_fruits = []
for fruit in fruits:
upper_fruits.append(fruit.upper())
print(upper_fruits) # ['APPLE', 'BANANA', 'GRAPE']
# ✅ 리스트 컴프리헨션 (1줄)
upper_fruits = [fruit.upper() for fruit in fruits]
print(upper_fruits) # ['APPLE', 'BANANA', 'GRAPE']
언제 사용하면 좋을까?
적합한 상황
- 기존 리스트를 변환할 때
- 특정 조건의 요소만 필터링할 때
- 간단한 수학 연산을 적용할 때
- 문자열 리스트를 처리할 때
부적합한 상황
- 로직이 복잡할 때 (3줄 이상의 변환)
- 부작용(side effect)이 있는 함수를 호출할 때
- 가독성이 떨어질 때
1
2
3
4
5
6
7
# ✅ 좋은 예: 간단한 변환
doubled = [x * 2 for x in numbers]
# ❌ 나쁜 예: 복잡한 로직
result = [complex_function(x, y, z) if condition1 else other_function(x)
for x in list1 if x > 0 for y in list2 if y < 10]
# 너무 복잡! 일반 반복문이 더 나음
🎯 학습 목표 2: 기본 문법 익히기
기본 문법 구조
핵심 패턴: [표현식 for 변수 in 반복가능객체]
1
[무엇을 만들지 for 각_요소 in 어디서_가져올지]
문법 요소 분해
| 요소 | 설명 | 예시 |
|---|---|---|
표현식 | 각 요소에 적용할 변환 | i * 2, fruit.upper() |
for 변수 | 반복 변수 | for i, for fruit |
in 반복가능객체 | 데이터 소스 | in range(10), in fruits |
기본 패턴 1: 값 그대로 복사
1
2
3
4
5
6
7
8
9
10
11
12
13
# 0부터 4까지
numbers = [i for i in range(5)]
print(numbers) # [0, 1, 2, 3, 4]
# 리스트 복사
original = [1, 2, 3]
copied = [x for x in original]
print(copied) # [1, 2, 3]
# 문자열 분리
text = "hello"
chars = [c for c in text]
print(chars) # ['h', 'e', 'l', 'l', 'o']
기본 패턴 2: 값 변환
1
2
3
4
5
6
7
8
9
10
11
# 제곱
squares = [i ** 2 for i in range(5)]
print(squares) # [0, 1, 4, 9, 16]
# 세제곱
cubes = [i ** 3 for i in range(1, 6)]
print(cubes) # [1, 8, 27, 64, 125]
# 2배
doubled = [i * 2 for i in range(5)]
print(doubled) # [0, 2, 4, 6, 8]
기본 패턴 3: 문자열 메서드 적용
1
2
3
4
5
6
7
8
9
10
11
12
13
fruits = ["apple", "banana", "grape"]
# 대문자 변환
upper = [fruit.upper() for fruit in fruits]
print(upper) # ['APPLE', 'BANANA', 'GRAPE']
# 첫 글자만 대문자
capitalized = [fruit.capitalize() for fruit in fruits]
print(capitalized) # ['Apple', 'Banana', 'Grape']
# 길이 계산
lengths = [len(fruit) for fruit in fruits]
print(lengths) # [5, 6, 5]
기본 패턴 4: 튜플 생성
1
2
3
4
5
6
7
8
# 숫자와 제곱 쌍
pairs = [(i, i**2) for i in range(5)]
print(pairs) # [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16)]
# 인덱스와 값 쌍
fruits = ["apple", "banana", "grape"]
indexed = [(i, fruit) for i, fruit in enumerate(fruits)]
print(indexed) # [(0, 'apple'), (1, 'banana'), (2, 'grape')]
기본 패턴 5: 함수 적용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 내장 함수 적용
numbers = [-2, -1, 0, 1, 2]
absolutes = [abs(n) for n in numbers]
print(absolutes) # [2, 1, 0, 1, 2]
# 사용자 정의 함수
def double(x):
return x * 2
doubled = [double(i) for i in range(5)]
print(doubled) # [0, 2, 4, 6, 8]
# 람다 함수
squared = [(lambda x: x**2)(i) for i in range(5)]
print(squared) # [0, 1, 4, 9, 16]
range()와 함께 사용하기
1
2
3
4
5
6
7
8
9
10
11
# 1부터 10까지
numbers = [i for i in range(1, 11)]
print(numbers) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 짝수만 (step=2)
evens = [i for i in range(0, 11, 2)]
print(evens) # [0, 2, 4, 6, 8, 10]
# 역순
reversed_nums = [i for i in range(10, 0, -1)]
print(reversed_nums) # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
🎯 학습 목표 3: 조건문 사용하기
if 조건 (필터링)
패턴: [표현식 for 변수 in 반복가능객체 if 조건]
조건이 True인 요소만 포함됩니다.
예제 1: 짝수만 필터링
1
2
3
4
5
6
7
8
9
10
# ❌ 전통적 방법
evens = []
for i in range(10):
if i % 2 == 0:
evens.append(i)
print(evens) # [0, 2, 4, 6, 8]
# ✅ 리스트 컴프리헨션
evens = [i for i in range(10) if i % 2 == 0]
print(evens) # [0, 2, 4, 6, 8]
예제 2: 양수만 필터링
1
2
3
4
5
6
7
8
9
10
11
numbers = [-2, -1, 0, 1, 2, 3]
positives = [n for n in numbers if n > 0]
print(positives) # [1, 2, 3]
# 음수만
negatives = [n for n in numbers if n < 0]
print(negatives) # [-2, -1]
# 0이 아닌 값만
non_zeros = [n for n in numbers if n != 0]
print(non_zeros) # [-2, -1, 1, 2, 3]
예제 3: 문자열 필터링
1
2
3
4
5
6
7
8
9
10
11
12
13
words = ["hi", "hello", "world", "python", "a"]
# 길이가 5 이상인 단어만
long_words = [w for w in words if len(w) >= 5]
print(long_words) # ['hello', 'world', 'python']
# 'o'가 포함된 단어만
with_o = [w for w in words if 'o' in w]
print(with_o) # ['hello', 'world', 'python']
# 대문자로 시작하지 않는 단어만
lowercase_start = [w for w in words if not w[0].isupper()]
print(lowercase_start) # 모든 단어 (다 소문자 시작)
if-else (값 변경)
패턴: [A if 조건 else B for 변수 in 반복가능객체]
조건에 따라 다른 값을 생성합니다.
1
2
3
4
5
6
7
8
# 짝수는 "짝", 홀수는 "홀"
result = ["짝" if i % 2 == 0 else "홀" for i in range(5)]
print(result) # ['짝', '홀', '짝', '홀', '짝']
# 양수는 그대로, 음수/0은 0으로
numbers = [-2, -1, 0, 1, 2]
result = [n if n > 0 else 0 for n in numbers]
print(result) # [0, 0, 0, 1, 2]
복합 조건
1
2
3
4
5
6
7
8
9
10
11
# 여러 조건 결합 (and)
numbers = [i for i in range(20) if i % 2 == 0 if i % 3 == 0]
print(numbers) # [0, 6, 12, 18] (2와 3의 공배수)
# 또는 (하나의 if문으로)
numbers = [i for i in range(20) if i % 2 == 0 and i % 3 == 0]
print(numbers) # [0, 6, 12, 18]
# or 조건
numbers = [i for i in range(10) if i % 2 == 0 or i % 3 == 0]
print(numbers) # [0, 2, 3, 4, 6, 8, 9]
🎯 학습 목표 4: 중첩 컴프리헨션 이해하기
중첩 반복문 (다중 for)
패턴: [표현식 for 변수1 in 반복가능객체1 for 변수2 in 반복가능객체2]
1
2
3
4
5
6
7
8
# 좌표 생성 (3x3)
coordinates = [(x, y) for x in range(3) for y in range(3)]
print(coordinates)
# [(0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), (2,2)]
# 구구단 (2단~9단)
multiplication = [f"{i}x{j}={i*j}" for i in range(2, 10) for j in range(1, 10)]
print(multiplication[:5]) # ['2x1=2', '2x2=4', '2x3=6', '2x4=8', '2x5=10']
2차원 리스트 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 3x3 영행렬
matrix = [[0 for _ in range(3)] for _ in range(3)]
print(matrix)
# [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
# 곱셈표 (3x3)
table = [[i*j for j in range(1, 4)] for i in range(1, 4)]
print(table)
# [[1, 2, 3], [2, 4, 6], [3, 6, 9]]
# 5x5 단위 행렬
identity = [[1 if i==j else 0 for j in range(5)] for i in range(5)]
print(identity)
# [[1, 0, 0, 0, 0],
# [0, 1, 0, 0, 0],
# [0, 0, 1, 0, 0],
# [0, 0, 0, 1, 0],
# [0, 0, 0, 0, 1]]
2차원 리스트 평탄화 (Flatten)
1
2
3
4
5
6
7
8
9
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# 평탄화
flat = [num for row in matrix for num in row]
print(flat) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 조건 추가: 짝수만
even_flat = [num for row in matrix for num in row if num % 2 == 0]
print(even_flat) # [2, 4, 6, 8]
💡 실전 팁 & 주의사항
Tip 1: if와 if-else 위치 차이
1
2
3
4
5
6
7
8
9
10
11
12
# ❌ 헷갈리기 쉬운 부분
# if는 맨 뒤 (필터링)
evens = [i for i in range(10) if i % 2 == 0]
# if-else는 맨 앞 (값 변경)
result = ["짝" if i % 2 == 0 else "홀" for i in range(5)]
# ❌ 이렇게 쓰면 에러!
# result = [i for i in range(10) if i % 2 == 0 else 0] # SyntaxError!
# ✅ 올바른 방법
result = [i if i % 2 == 0 else 0 for i in range(10)]
Tip 2: 너무 복잡하면 분리하기
1
2
3
4
5
6
7
8
# ❌ 가독성이 떨어지는 예
result = [[i*j for j in range(1, 10) if j % 2 == 0]
for i in range(1, 10) if i % 2 == 1]
# ✅ 단계별로 분리
odd_numbers = [i for i in range(1, 10) if i % 2 == 1]
even_numbers = [j for j in range(1, 10) if j % 2 == 0]
result = [[i*j for j in even_numbers] for i in odd_numbers]
Tip 3: 빈 리스트 주의
1
2
3
4
5
6
7
words = []
# 빈 리스트에 컴프리헨션 적용하면 빈 리스트 반환
upper_words = [w.upper() for w in words]
print(upper_words) # []
# 에러는 안 나지만 결과가 없음
Tip 4: 언더스코어(_) 활용
1
2
3
4
5
6
# 변수를 사용하지 않을 때는 _
zeros = [0 for _ in range(10)]
print(zeros) # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# 2차원 리스트
matrix = [[0 for _ in range(3)] for _ in range(3)]
Tip 5: map()과 filter() 대신 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
numbers = [1, 2, 3, 4, 5]
# ❌ map() 사용 (함수형 프로그래밍)
doubled = list(map(lambda x: x * 2, numbers))
# ✅ 리스트 컴프리헨션 (Pythonic)
doubled = [x * 2 for x in numbers]
# ❌ filter() 사용
evens = list(filter(lambda x: x % 2 == 0, numbers))
# ✅ 리스트 컴프리헨션
evens = [x for x in numbers if x % 2 == 0]
Tip 6: 성능 고려사항
1
2
3
4
5
6
# 작은 리스트: 컴프리헨션이 빠름
small = [i**2 for i in range(100)]
# 매우 큰 리스트: 메모리 고려 필요
# Generator expression 사용 고려
large = (i**2 for i in range(1000000)) # 괄호 () 사용
🧪 연습 문제
문제 1: 학생 성적 데이터 처리 시스템
과제: 학생들의 점수 리스트를 여러 조건으로 필터링하고 변환하는 프로그램을 작성하세요. 리스트 컴프리헨션의 다양한 패턴을 활용합니다.
초기 데이터:
1
2
3
4
5
6
7
8
9
10
students = [
{"name": "홍길동", "score": 85},
{"name": "김철수", "score": 92},
{"name": "이영희", "score": 78},
{"name": "박민수", "score": 95},
{"name": "정수진", "score": 67},
{"name": "최지훈", "score": 88},
{"name": "한미영", "score": 73},
{"name": "윤성호", "score": 90}
]
요구사항:
- 80점 이상인 학생들의 이름만 추출하기
- 모든 학생의 점수를 10% 증가시킨 새 리스트 만들기 (소수점 첫째 자리)
- 학점 판정하기:
- 90점 이상: “A”
- 80점 이상: “B”
- 70점 이상: “C”
- 나머지: “D”
- 합격자(70점 이상)와 불합격자(70점 미만)로 분류하기
- 각 학생의 이름과 학점을 튜플 리스트로 만들기:
[("이름", "학점"), ...] - 통계: 평균, 최고점, 최저점, 합격률 계산하기
💡 힌트
- 필터링:
[변수 for 변수 in 리스트 if 조건] - 변환:
[표현식 for 변수 in 리스트] - if-else:
[A if 조건 else B for 변수 in 리스트] - 딕셔너리 접근:
student["name"],student["score"] - 학점 판정: if-elif-else 체이닝
✅ 정답
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
students = [
{"name": "홍길동", "score": 85},
{"name": "김철수", "score": 92},
{"name": "이영희", "score": 78},
{"name": "박민수", "score": 95},
{"name": "정수진", "score": 67},
{"name": "최지훈", "score": 88},
{"name": "한미영", "score": 73},
{"name": "윤성호", "score": 90}
]
print("===== 학생 성적 데이터 처리 =====\n")
# 1. 80점 이상인 학생들의 이름 추출
high_scorers = [s["name"] for s in students if s["score"] >= 80]
print(f"1. 80점 이상 학생들:")
print(f" {', '.join(high_scorers)}")
print(f" 총 {len(high_scorers)}명\n")
# 2. 모든 학생의 점수를 10% 증가 (보너스 점수)
bonus_scores = [round(s["score"] * 1.1, 1) for s in students]
print(f"2. 보너스 점수 (10% 증가):")
for i, student in enumerate(students):
print(f" {student['name']}: {student['score']}점 → {bonus_scores[i]}점")
print()
# 3. 학점 판정 (원본 점수 기준)
grades = [
"A" if s["score"] >= 90 else
"B" if s["score"] >= 80 else
"C" if s["score"] >= 70 else
"D"
for s in students
]
print(f"3. 학점 판정:")
for i, student in enumerate(students):
print(f" {student['name']}: {student['score']}점 → {grades[i]}학점")
print()
# 4. 합격자(70점 이상)와 불합격자 분류
passed = [s["name"] for s in students if s["score"] >= 70]
failed = [s["name"] for s in students if s["score"] < 70]
print(f"4. 합격/불합격 분류:")
print(f" 합격 ({len(passed)}명): {', '.join(passed)}")
print(f" 불합격 ({len(failed)}명): {', '.join(failed) if failed else '없음'}")
print()
# 5. 이름과 학점 튜플 리스트
name_grade_pairs = [
(s["name"],
"A" if s["score"] >= 90 else
"B" if s["score"] >= 80 else
"C" if s["score"] >= 70 else
"D")
for s in students
]
print(f"5. 이름-학점 튜플 리스트:")
for name, grade in name_grade_pairs:
print(f" {name}: {grade}")
print()
# 6. 통계 계산
scores = [s["score"] for s in students]
average = sum(scores) / len(scores)
max_score = max(scores)
min_score = min(scores)
pass_rate = len(passed) / len(students) * 100
print(f"6. 통계:")
print(f" 평균 점수: {average:.1f}점")
print(f" 최고 점수: {max_score}점")
print(f" 최저 점수: {min_score}점")
print(f" 합격률: {pass_rate:.1f}%")
# 추가: 학점별 인원 수
grade_a = len([g for g in grades if g == "A"])
grade_b = len([g for g in grades if g == "B"])
grade_c = len([g for g in grades if g == "C"])
grade_d = len([g for g in grades if g == "D"])
print(f"\n7. 학점별 분포:")
print(f" A학점: {grade_a}명")
print(f" B학점: {grade_b}명")
print(f" C학점: {grade_c}명")
print(f" D학점: {grade_d}명")
# 추가: 상위 3명
top_3 = sorted(students, key=lambda x: x["score"], reverse=True)[:3]
print(f"\n8. 상위 3명:")
for i, student in enumerate(top_3, 1):
print(f" {i}등: {student['name']} ({student['score']}점)")
출력:
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
===== 학생 성적 데이터 처리 =====
1. 80점 이상 학생들:
홍길동, 김철수, 박민수, 최지훈, 윤성호
총 5명
2. 보너스 점수 (10% 증가):
홍길동: 85점 → 93.5점
김철수: 92점 → 101.2점
이영희: 78점 → 85.8점
박민수: 95점 → 104.5점
정수진: 67점 → 73.7점
최지훈: 88점 → 96.8점
한미영: 73점 → 80.3점
윤성호: 90점 → 99.0점
3. 학점 판정:
홍길동: 85점 → B학점
김철수: 92점 → A학점
이영희: 78점 → C학점
박민수: 95점 → A학점
정수진: 67점 → D학점
최지훈: 88점 → B학점
한미영: 73점 → C학점
윤성호: 90점 → A학점
4. 합격/불합격 분류:
합격 (7명): 홍길동, 김철수, 이영희, 박민수, 최지훈, 한미영, 윤성호
불합격 (1명): 정수진
5. 이름-학점 튜플 리스트:
홍길동: B
김철수: A
이영희: C
박민수: A
정수진: D
최지훈: B
한미영: C
윤성호: A
6. 통계:
평균 점수: 83.5점
최고 점수: 95점
최저 점수: 67점
합격률: 87.5%
7. 학점별 분포:
A학점: 3명
B학점: 2명
C학점: 2명
D학점: 1명
8. 상위 3명:
1등: 박민수 (95점)
2등: 김철수 (92점)
3등: 윤성호 (90점)
문제 2: 데이터 변환 및 중첩 리스트 컴프리헨션
과제: 중첩 리스트를 활용하여 2차원 데이터를 생성하고 변환하는 프로그램을 작성하세요.
초기 데이터:
1
2
3
4
5
6
# 3개 반의 학생 점수 (반별 5명)
classes = [
[85, 92, 78, 95, 88], # 1반
[90, 85, 88, 92, 87], # 2반
[78, 82, 85, 79, 91] # 3반
]
요구사항:
- 각 반의 평균 점수를 계산하여 리스트로 만들기
- 모든 반의 모든 점수를 하나의 1차원 리스트로 평탄화하기
- 80점 이상인 학생 수를 반별로 계산하기
- 구구단 2~5단을 2차원 리스트로 생성하기 (중첩 컴프리헨션)
- 좌표 평면의 격자점 생성하기: x는 0~2, y는 0~2 → [(0,0), (0,1), (0,2), …]
- FizzBuzz 문제를 1부터 30까지 리스트로 만들기:
- 15의 배수: “FizzBuzz”
- 3의 배수: “Fizz”
- 5의 배수: “Buzz”
- 나머지: 숫자 그대로
💡 힌트
- 평균:
sum(리스트) / len(리스트) - 평탄화:
[item for sublist in 리스트 for item in sublist] - 중첩 컴프리헨션:
[[내부식 for j in ...] for i in ...] - 튜플 생성:
[(x, y) for x in ... for y in ...] - if-elif-else 체이닝: 조건을 앞에서부터 검사
✅ 정답
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
classes = [
[85, 92, 78, 95, 88], # 1반
[90, 85, 88, 92, 87], # 2반
[78, 82, 85, 79, 91] # 3반
]
print("===== 데이터 변환 및 중첩 리스트 컴프리헨션 =====\n")
# 1. 각 반의 평균 점수
averages = [sum(class_scores) / len(class_scores) for class_scores in classes]
print("1. 반별 평균 점수:")
for i, avg in enumerate(averages, 1):
print(f" {i}반: {avg:.1f}점")
print()
# 2. 모든 점수를 하나의 1차원 리스트로 평탄화
all_scores = [score for class_scores in classes for score in class_scores]
print(f"2. 평탄화된 전체 점수:")
print(f" {all_scores}")
print(f" 총 {len(all_scores)}명의 점수")
print()
# 3. 80점 이상인 학생 수 (반별)
high_scorers_count = [len([s for s in class_scores if s >= 80]) for class_scores in classes]
print("3. 반별 80점 이상 학생 수:")
for i, count in enumerate(high_scorers_count, 1):
print(f" {i}반: {count}명 / {len(classes[i-1])}명")
print()
# 4. 구구단 2~5단 (2차원 리스트)
gugudan = [[i * j for j in range(1, 10)] for i in range(2, 6)]
print("4. 구구단 2~5단:")
for i, dan in enumerate(gugudan, start=2):
print(f" {i}단: {dan}")
print()
# 구구단 문자열 버전 (보기 좋게)
gugudan_str = [[f"{i}×{j}={i*j}" for j in range(1, 10)] for i in range(2, 6)]
print(" [문자열 버전]")
for i, dan in enumerate(gugudan_str, start=2):
print(f" {i}단: {', '.join(dan[:3])} ...")
print()
# 5. 좌표 평면의 격자점 생성 (0~2 × 0~2)
coordinates = [(x, y) for x in range(3) for y in range(3)]
print("5. 좌표 평면 격자점 (0~2 × 0~2):")
print(f" {coordinates}")
print(f" 총 {len(coordinates)}개의 좌표")
# 3×3 격자 시각화
print("\n [격자 시각화]")
for y in range(2, -1, -1):
row_coords = [(x, y) for x in range(3)]
print(f" y={y}: {row_coords}")
print()
# 6. FizzBuzz (1~30)
fizzbuzz = [
"FizzBuzz" if i % 15 == 0 else
"Fizz" if i % 3 == 0 else
"Buzz" if i % 5 == 0 else
i
for i in range(1, 31)
]
print("6. FizzBuzz (1~30):")
print(f" {fizzbuzz}")
# FizzBuzz 통계
fizz_count = len([x for x in fizzbuzz if x == "Fizz"])
buzz_count = len([x for x in fizzbuzz if x == "Buzz"])
fizzbuzz_count = len([x for x in fizzbuzz if x == "FizzBuzz"])
number_count = len([x for x in fizzbuzz if isinstance(x, int)])
print(f"\n [통계]")
print(f" Fizz: {fizz_count}개")
print(f" Buzz: {buzz_count}개")
print(f" FizzBuzz: {fizzbuzz_count}개")
print(f" 숫자: {number_count}개")
# 추가: 전체 통계
print(f"\n7. 전체 학생 통계:")
total_avg = sum(all_scores) / len(all_scores)
total_max = max(all_scores)
total_min = min(all_scores)
total_high = len([s for s in all_scores if s >= 80])
print(f" 전체 평균: {total_avg:.1f}점")
print(f" 최고 점수: {total_max}점")
print(f" 최저 점수: {total_min}점")
print(f" 80점 이상: {total_high}명 ({total_high/len(all_scores)*100:.1f}%)")
출력:
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
===== 데이터 변환 및 중첩 리스트 컴프리헨션 =====
1. 반별 평균 점수:
1반: 87.6점
2반: 88.4점
3반: 83.0점
2. 평탄화된 전체 점수:
[85, 92, 78, 95, 88, 90, 85, 88, 92, 87, 78, 82, 85, 79, 91]
총 15명의 점수
3. 반별 80점 이상 학생 수:
1반: 4명 / 5명
2반: 5명 / 5명
3반: 3명 / 5명
4. 구구단 2~5단:
2단: [2, 4, 6, 8, 10, 12, 14, 16, 18]
3단: [3, 6, 9, 12, 15, 18, 21, 24, 27]
4단: [4, 8, 12, 16, 20, 24, 28, 32, 36]
5단: [5, 10, 15, 20, 25, 30, 35, 40, 45]
[문자열 버전]
2단: 2×1=2, 2×2=4, 2×3=6 ...
3단: 3×1=3, 3×2=6, 3×3=9 ...
4단: 4×1=4, 4×2=8, 4×3=12 ...
5단: 5×1=5, 5×2=10, 5×3=15 ...
5. 좌표 평면 격자점 (0~2 × 0~2):
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
총 9개의 좌표
[격자 시각화]
y=2: [(0, 2), (1, 2), (2, 2)]
y=1: [(0, 1), (1, 1), (2, 1)]
y=0: [(0, 0), (1, 0), (2, 0)]
6. FizzBuzz (1~30):
[1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz', 11, 'Fizz', 13, 14, 'FizzBuzz', 16, 17, 'Fizz', 19, 'Buzz', 'Fizz', 22, 23, 'Fizz', 'Buzz', 26, 'Fizz', 28, 29, 'FizzBuzz']
[통계]
Fizz: 8개
Buzz: 4개
FizzBuzz: 2개
숫자: 16개
7. 전체 학생 통계:
전체 평균: 86.3점
최고 점수: 95점
최저 점수: 78점
80점 이상: 12명 (80.0%)
🎯 연습 문제 핵심 포인트
문제 1에서 배운 것:
- 조건 필터링:
[x for x in 리스트 if 조건] - 값 변환:
[표현식 for x in 리스트] - if-else 체이닝: 복잡한 조건 판정 (학점)
- 딕셔너리 리스트 처리: 실제 데이터 구조 다루기
- 통계 계산: 평균, 최고/최저, 비율
문제 2에서 배운 것:
- 중첩 리스트 컴프리헨션: 2차원 데이터 생성
- 평탄화: 다차원 → 1차원 변환
- 좌표 생성: 데카르트 곱(Cartesian product)
- FizzBuzz: if-elif-else 체이닝의 실전 활용
- 다중 변환: 여러 방식으로 데이터 가공
📝 오늘 배운 내용 정리
- 리스트 컴프리헨션: 반복문과 조건문을 하나의 표현식으로 결합하여 리스트 생성
- 기본 문법:
[표현식 for 변수 in 반복가능객체] - if 조건:
[표현식 for 변수 in 반복가능객체 if 조건]- 필터링 - if-else:
[A if 조건 else B for 변수 in 반복가능객체]- 값 변경 - 중첩 컴프리헨션: 2차원 리스트 생성, 평탄화
- 장점: 간결성, 가독성, 성능 (30-40% 빠름)
🔗 관련 자료
📚 이전 학습
Day 17: 문자열 메서드 활용 ⭐⭐
어제는 문자열 메서드로 텍스트를 다루는 방법을 배웠습니다!
📚 다음 학습
Day 19: 딕셔너리 컴프리헨션 ⭐⭐
내일은 딕셔너리를 간결하게 만드는 방법을 배웁니다!
“늦었다고 생각할 때가 가장 빠른 시기입니다!” 🚀
Day 18/100 Phase 2: 자료형 마스터하기 #100DaysOfPython
