list(dict) 학습문자열 메서드 정리 → 문자열 문제 6문제 → 집합(set) 개념 + 연산 → 집합 문제 4문제 → 종합 복습 1문제
| 메서드 | 설명 | Java 비교 |
|---|---|---|
s.split(",") | 구분자로 쪼개서 리스트 반환 | s.split(",") (배열 반환) |
",".join(lst) | 리스트를 구분자로 합치기 | String.join(",", arr) |
s.replace("a","b") | 치환 (새 문자열 반환) | 동일 |
s.strip() | 양쪽 공백 제거 | s.trim() |
s.find("x") | 찾으면 인덱스, 없으면 -1 | s.indexOf("x") |
s.index("x") | 찾으면 인덱스, 없으면 에러! | — |
s.count("a") | 특정 문자/문자열 등장 횟수 | — (직접 구현) |
s.isdigit() | 전부 숫자인지 | s.matches("\\d+") |
s.isalpha() | 전부 알파벳인지 | — |
s.upper() / s.lower() | 대/소문자 변환 | 동일 |
s.startswith("x") | 접두사 확인 | 동일 |
s.zfill(n) | 왼쪽 0 채우기 | — |
Java와 대부분 비슷하지만, count(), isdigit(), zfill() 같은 건 Python만의 편의 메서드다.
s = "hello"
s[0] = "H" # ❌ 에러! 문자열은 수정 불가
s = "H" + s[1:] # ✅ 새 문자열 생성
"a b c".split() # ['a', 'b', 'c'] — 연속 공백 자동 처리
"a b c".split(" ") # ['a', '', 'b', '', 'c'] — 빈 문자열 포함!
인자 없이 split()을 호출하면 연속 공백을 하나로 처리하지만, split(" ")은 공백 하나하나를 구분자로 인식해서 빈 문자열이 생긴다. 이 차이가 시험에서 함정으로 나온다.
",".join([1, 2, 3]) # ❌ 에러!
",".join(str(x) for x in [1, 2, 3]) # ✅ "1,2,3"
text.lower().replace(" ", "") # 소문자 변환 + 공백 제거를 한 줄에
문자열 메서드는 새 문자열을 반환하므로, 연속으로 이어붙일 수 있다.
def count_word(sentence, word):
converted = sentence.lower()
target = word.lower()
# 이후 비교
digits = ""
for ch in phone:
if ch.isdigit():
digits += ch
def is_palindrome(text):
cleaned = text.lower().replace(" ", "")
return cleaned == cleaned[::-1]
| 특징 | 설명 |
|---|---|
| 중복 없음 | {1, 1, 2} → {1, 2} |
| 순서 없음 | 인덱싱 불가 (s[0] ❌) |
| 변경 가능 | 추가/삭제 가능 |
s = {1, 2, 3}
s = set([1, 2, 2, 3]) # 리스트에서 변환 → {1, 2, 3}
empty = set() # ⚠️ {}는 빈 딕셔너리!
{}로 빈 집합을 만들 수 없다는 점이 자주 혼동되는 포인트다.
s.add(4) # 하나 추가
s.remove(4) # 삭제 (없으면 KeyError!)
s.discard(4) # 삭제 (없어도 에러 안 남)
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
a | b # 합집합: {1, 2, 3, 4, 5, 6}
a & b # 교집합: {3, 4}
a - b # 차집합: {1, 2}
a ^ b # 대칭차집합: {1, 2, 5, 6}
→ 연산자와 메서드는 결과가 동일하다.
| 연산 | 연산자 | 메서드 |
|---|---|---|
| 합집합 | a \| b | a.union(b) |
| 교집합 | a & b | a.intersection(b) |
| 차집합 | a - b | a.difference(b) |
| 대칭차집합 | a ^ b | a.symmetric_difference(b) |
COS Pro에서는 연산자 버전이 더 자주 출제된다. 메서드 이름은 영어 뜻 그대로라 외우기 쉽다.
두 리스트에서 공통 원소만 추출하여 정렬된 리스트로 반환하는 문제.
def common_elements(list1, list2):
set1 = set(list1)
set2 = set(list2)
common = set1 & set2 # 교집합
return sorted(common) # 정렬된 리스트로 반환
자주 쓰는 패턴: 중복 제거 후 정렬
nums = [3, 1, 2, 1, 3]
result = sorted(set(nums)) # [1, 2, 3]
문자열 리스트에서 중복을 제거하되, 원래 등장 순서를 유지하여 반환하는 문제. 단순 set()은 순서를 보장하지 않으므로 별도 패턴이 필요하다.
def unique_ordered(items):
seen = set() # ⚠️ 빈 set으로 시작!
result = []
for item in items:
if item not in seen:
seen.add(item)
result.append(item)
return result
여기서 seen을 set(items)로 시작하면 이미 모든 항목이 "본 것"으로 처리되어 아무것도 추가되지 않는다. 빈 set()으로 시작해야 하나씩 추적할 수 있다.
또한 item not in result(리스트 검색)보다 item not in seen(set 검색)이 훨씬 빠르다. 리스트는 O(n), set은 O(1)이므로 "이미 봤는지 확인"은 set을 쓰는 게 정석이다.
학생들의 수강 과목이 딕셔너리로 주어질 때, 모든 학생이 공통으로 수강하는 과목을 정렬하여 반환하는 문제. 여러 집합의 교집합을 누적하는 패턴이 핵심이다.
def common_courses(students):
courses_list = list(students.values())
result = set(courses_list[0]) # 첫 번째 값으로 초기화
for courses in courses_list[1:]: # 나머지 순회
result = result & set(courses) # 교집합 누적
return sorted(result)
이 패턴의 핵심:
1. dict.values()를 list()로 변환하면 인덱스 접근 가능
2. 첫 번째 값으로 초기화 → 나머지 순회하며 누적 연산
3. 학생 수가 몇 명이든 동작하는 일반화된 코드
처음에는 list1, list2, list3 = students.values()로 3명 고정 언패킹을 했지만, 이러면 학생 수가 바뀔 때 깨진다. 하드코딩 대신 for문으로 일반화하는 습관이 중요하다.
단어 리스트를 받아서, 각 단어의 첫 글자를 키로 하고 해당 글자로 시작하는 단어들의 리스트를 값으로 하는 딕셔너리를 반환하는 문제. 단어는 소문자 통일, 중복 제거, 알파벳 순 정렬이 필요하다. 문자열 + 딕셔너리 + 집합을 조합한 종합 문제:
def group_by_initial(words):
list1 = sorted(set([word.lower() for word in words])) # 전처리
result = {}
for word in list1:
if word[0] in result:
result[word[0]].append(word)
else:
result[word[0]] = [word]
return result
전처리(lower + set + sorted)를 먼저 완료한 뒤 딕셔너리를 구성하는 접근이 깔끔하다. sorted를 먼저 했기 때문에 각 그룹 안의 단어들도 자동으로 정렬된 상태가 된다.