- TIL. 문제 풀이. 목차
[오늘 한일]
- 알고리즘 문제 풀이
- 도커 강의 수강
[오늘 배운점]
파이썬
알고리즘 문제를 풀며 알게된 점을 적는다.
<리스트 컴프리헨션 이중 반복 시 순서관계>
이전에 이중 리스트 컴프리헨션에 대해 익힌적이 있다.
그때는 상위 반복문에 요소를 하위 반복문에서 참조하려면,
바깥 컴프리헨션 안에서 컴프리헨션을 한번 더 하는 방법밖에 없는걸로 이해하게 되었다.
그런데 그런 문제가 아니었다.
오늘 문제풀이를 하며 팀원분께 배웠는데,
리스트 컴프리헨션에 반복문을 나열할때 순서적으로 앞쪽이 먼저가 된다는 것이다.
[x+y for i, x in enumerate(numbers) for j, y in enumerate(numbers) if i != j]
# [작성상 앞쪽 반복문이 먼저, 뒤 반복문이 후위이다.]
오늘 작성한 리스트 컴프리헨션이다.
작성상 앞쪽이 먼저고, 뒤쪽이 그 하위 반복문이 된다.
이렇게 뒤쪽 반복문에서 앞쪽 반복문의 요소인 i를 잘 가져다 쓸수있다.
나는 왜그랬는지 뒤쪽이 먼저 일거라고 생각하고 있었다.
하지만 앞쪽이 먼저다.
<enumerate 시작숫자 정하기>
범위와 요소를 동시에 제공해주는 enumerate 함수가 있다.
팀원분께 배웠는데,
enumerate에서 첫째 반환값은 (보통 i라고 표현하게 되는) 정확히 보자면 반복횟수를 말한다.
기대하는 대로 1 > 2 > 3 순으로 올라가게 된다.
enumrate(이터러블, 숫자)함수 뒤쪽 인자에 숫자를 실어주게되면,
해당 숫자를 반복 카운트의 시작숫자로 삼게 된다.
이때 당연하게도 변수를 정할수도 있고,
그럼 이런 작성법이 가능하다.
팀원분이 작성하신 코드다.
for i, x in enumerate(numbers):
for j, y in enumerate(numbers[i:], i+1):
check = x+y
이렇게 함으로써 상위의 반복시 마다,
하위 반복은 같은 리스트를 한요소씩 적게 반복하게 되면서,
하나씩 밀리는 인덱스값인 j를 얻을수 있다.
※ 한편, 같은 문제에 대해 상단의 내코드와 팀원분의 코드는,
경우의 수를 탐색하는 방법이 틀리다.
나는 모든 요소를 자신을 뺀 모든 요소에 대해 처리하고,
팀원분 코드는 모든 요소를 이미 처리한 경우는 제외하며 처리한다.
※ 전자의 방법은 pop을 떠올리기 쉽지만 나는 인덱스 검사로 코드를 작성했다.
후자의 방법은 역시 슬라이싱이 적절해보인다.
<range만 반복하지만 요소는 가져온다>
팀원분 작성코드를 보며 한가지 또다른 포인트를 얻었다.
range를 이용해 리스트의 요소 개수만큼 반복을 한다.
그리고 반복문 안에서는 i 값을 인덱스 삼아 리스트에서 해당 요소를 가져다쓴다.
enumerate가 없는 다른 언어에서 보통 사용하는 방법이다.
참조하는 리스트가 부동적이라면 이방법도 한가지 해법중 하나이다.
<반복문 요소 거꾸로 반복하기>
요소를 반복하는 반복문에서 반복을 거꾸로 실행하고 싶다면 어떻게 해야할까.
오늘 문제를 풀다가 맞닥뜨려본 상황이다.
answer = [x for x in reversed(strings)]
answer = [x for x in strings[::-1]]
이터러블한 값을 거꾸로 반환하는 방법은 두가지가 있다.
하나는 reversed함수이다.
다른 하나는 슬라이싱 3번째 요소에 -1을 주는 것이다.
두개 동작은 같다.
한편, 리스트의 요소를 거꾸로 제공하는 것도 방법이지만,
완성된 리스트를 뒤집어 버리는것도 방법이다.
문제에 따라 필요하거나 적합한 방법이 다를수 있으니 기억해야겠다.
<리스트 count연산>
리스트에서 특정 요소의 개수를 세는건
리스트.count(x)로 할수 있는데 아주 유용하다.
선발대 강의에서 배웠던 거지만, 문제를 풀다보면 잘 기억나지 않고, 그냥 반복문으로 작성할때가 있다.
오늘도 그랬다.
결론, 리스트에서 x의 개수를 셀때는 반복문 작성 전에 count연산을 떠올리자.