파이썬 리스트 컴프리헨션 정리 | 코딩테스트에서 바로 쓰는 패턴 모음

리스트 컴프리헨션은 그냥 for문 짧게 쓰는 문법이 아니다.

코딩테스트에서는 보통

입력을 가공하거나, 조건에 맞는 값만 뽑거나, 간단한 변환을 한 줄로 처리할 때 제일 많이 쓴다.

즉, 이걸 문법 하나로만 보면 잘 안 남고,

반복 + 조건 + 변환을 한 번에 묶는 패턴으로 봐야 실전에서 손에 붙는다.

처음에는 나도 그냥 “짧게 쓰는 문법” 정도로만 봤는데,

막상 문제 풀다 보니까 이게 꽤 자주 나왔다.

  • 숫자 리스트 만들기
  • 조건에 맞는 값만 남기기
  • 문자열을 문자 단위로 쪼개기
  • 입력값을 가공해서 바로 리스트 만들기

이런 데서는 그냥 반복문보다 더 자연스럽다.


🔗 주제

파이썬 리스트 컴프리헨션 정리

+ 마지막에 연습문제 첨부합니다 필요하면 사용하시면 되어요


개념 요약

리스트 컴프리헨션 기본형은 이거다.

[표현식 for 변수 in 반복가능한값]

조건까지 붙으면 이렇게 간다.

[표현식 for 변수 in 반복가능한값 if 조건]

if-else가 같이 들어가면 이렇게 된다.

[참일때값 if 조건 else 거짓일때값 for 변수 in 반복가능한값]

형태는 몇 개 안 되는데,

코테에서는 이걸 굉장히 자주 변형해서 쓰게 된다.


✅ 자주 쓰는 패턴

1) 기본 리스트 만들기

numbers = [i for i in range(10)]
print(numbers)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

가장 기본형이다.

반복문 돌면서 append() 하는 걸 한 줄로 줄인 형태다.


2) 값 변환하기

squares = [i * i for i in range(1, 11)]
print(squares)  # [1, 4, 9, 16, ..., 100]

이건 코테에서 꽤 자주 나온다.

입력을 그대로 쓰지 않고, 어떤 규칙으로 가공할 때 많이 쓴다.


3) 조건 필터링하기

evens = [i for i in range(21) if i % 2 == 0]
print(evens)  # [0, 2, 4, ..., 20]

조건에 맞는 값만 남긴다.

이건 반복문 + if문보다 훨씬 깔끔하게 보일 때가 많다.


4) if-else 같이 쓰기

labels = ["even" if i % 2 == 0 else "odd" for i in range(10)]
print(labels)

값 자체를 바꿔서 넣을 때 쓴다.

이건 문법이 처음엔 좀 어색한데,

형태만 익숙해지면 금방 읽힌다.


5) 문자열 순회하기

chars = [ch for ch in "hello"]
print(chars)  # ['h', 'e', 'l', 'l', 'o']

리스트 컴프리헨션은 range()만 도는 게 아니다.

문자열도 바로 순회할 수 있다.


6) 리스트 안의 값 가공하기

lengths = [len(word) for word in ["apple", "banana", "kiwi"]]
print(lengths)  # [5, 6, 4]

이런 식으로 리스트 안의 각 원소를 가공해서 새 리스트를 만들 수도 있다.


코딩테스트에서 왜 자주 쓰는가

이건 결국 입력 가공이랑 연결돼서 그렇다.

코테에서 많이 하는 작업이 이런 거다.

  • 숫자 리스트 만들기
  • 특정 조건만 남기기
  • 문자열 쪼개기
  • 2차원 배열 만들기
  • 값 변환해서 바로 저장하기

즉, 리스트 컴프리헨션은

문법 그 자체보다 전처리 패턴에 더 가깝다.

예를 들어 이런 건 거의 전형적인 형태다.

nums = [int(x) for x in input().split()]

이건 사실 split + map으로도 가능하다.

nums = list(map(int, input().split()))

둘 다 맞는데,

리스트 컴프리헨션은 중간에 가공이 더 붙기 쉬워서 편할 때가 있다.

예를 들면:

nums = [int(x) * 2 for x in input().split()]

이건 map()보다 컴프리헨션 쪽이 읽기 더 편하다.


생각해야 하는 부분

리스트 컴프리헨션은 편하긴 한데,

무조건 짧게 쓰는 게 좋은 건 아니다.

그래서 실전에서는

어디까지 쓰면 좋은지를 같이 봐야 한다.


1. 반복 + 조건 + 간단한 변환까지가 제일 좋다

이 정도는 보통 괜찮다.

[x * x for x in range(10) if x % 2 == 0]

읽는 사람도 바로 이해할 수 있다.

즉,

  • 반복
  • 조건
  • 간단한 계산

여기까지는 리스트 컴프리헨션이 잘 맞는다.


2. 너무 많은 조건을 한 줄에 몰아넣으면 오히려 안 좋다

예를 들어 이런 식으로 길어지면

result = [x * 2 if x % 2 == 0 else x + 1 for x in nums if x > 0 if x < 100]

문법적으로는 가능해도 읽는 사람 입장에서 확 피곤해진다.

이럴 땐 그냥 for문으로 빼는 게 낫다.

즉, 리스트 컴프리헨션은

짧아서 좋은 게 아니라, 짧아도 읽히면 좋은 것이다.


3. 2중 for도 가능하지만, 남용하면 바로 가독성 깨진다

예를 들면 이런 식이다.

pairs = [(i, j) for i in range(3) for j in range(2)]
print(pairs)

이것도 코테에서 나오긴 한다.

근데 중첩이 늘어나면 바로 복잡해진다.

그래서 2중 for까진 종종 쓰지만,

그 이상부터는 좀 조심하는 게 낫다.


예외처리 / 주의할 점

⚠️ 1. if와 if-else 위치를 자주 헷갈린다

이건 처음에 제일 많이 헷갈린다.

조건 필터링

[i for i in range(10) if i % 2 == 0]

값 바꾸기

["even" if i % 2 == 0 else "odd" for i in range(10)]

즉,

  • if만 뒤에 붙으면 → 걸러내기
  • if else가 앞에 오면 → 값 바꾸기

이 차이를 구분해야 한다.


⚠️ 2. map이 더 자연스러운 경우도 있다

예를 들면 입력 숫자 여러 개를 그대로 정수 리스트로 바꾸는 건

nums = list(map(int, input().split()))

이쪽이 더 전형적이다.

반면 중간에 가공이 붙으면

nums = [int(x) * 2 for x in input().split()]

이쪽이 더 자연스럽다.

즉, 리스트 컴프리헨션이 항상 정답은 아니고

상황 따라 더 읽기 좋은 쪽을 고르는 게 맞다.


⚠️ 3. 한 줄에 다 우겨 넣으려고 하면 오히려 더 느려진다

짧게 쓰는 맛이 있다 보니

괜히 다 한 줄에 넣고 싶어진다.

근데 코테에서는

본인이 다시 봐도 이해 안 되는 코드면 오히려 손해다.

특히 디버깅해야 할 때

너무 꼬인 컴프리헨션은 오히려 더 불편하다.


내 시행착오

이 부분은 나도 꽤 공감 갔던 부분이다.


1. 그냥 “for문 줄인 문법”이라고만 생각했다

처음에는 진짜 그렇게만 봤다.

  • append 줄이기
  • 코드 짧게 쓰기

근데 실제로는 그보다

입력을 변환하는 패턴으로 더 자주 쓰였다.

이걸 늦게 봤다.


2. range만 도는 줄 알았다

처음엔 리스트 컴프리헨션 하면

무조건 range()만 생각났다.

근데 실제로는

  • 문자열
  • 리스트
  • split 결과
  • map 결과

이런 것도 다 바로 순회할 수 있다.

이걸 알고 나니까 훨씬 자주 쓰이기 시작했다.


3. if와 if-else 문법이 자꾸 헷갈렸다

이건 진짜 처음에 많이 꼬인다.

  • 뒤에 if 붙는 건 필터링
  • 앞에 if else 오는 건 값 변경

이 차이만 익숙해져도 훨씬 덜 헷갈린다.


4. 너무 복잡하게 쓰면 오히려 더 안 읽힌다는 걸 나중에 알았다

짧다고 무조건 좋은 게 아니었다.

결국 코테에서는

내가 다시 읽고 바로 이해되는 코드가 더 중요했다.

그래서 지금은

리스트 컴프리헨션도 짧고 단순할 때만 쓰는 쪽이 더 낫다고 본다.


한 줄 정리

리스트 컴프리헨션은 for문을 줄이는 문법이 아니라,

반복 + 조건 + 간단한 변환을 한 번에 처리하는 코테용 패턴으로 보는 게 더 잘 남는다.

LC,map,split_연습.pdf
0.31MB