[Python] 여러 list를 한 번에 iterate 하고 싶을 때
Introduction
파이썬을 사용하다 보면, 여러 개의 리스트에서 동시에 값을 iterate 해야 할 때가 많다.
예를 들어, 아래와 같이 과일의 이름을 저장하고 있는 fruit_list와 과일의 가격을 저장한 fruit_price_list가 각각 리스트로 주어졌을 때, 과일의 이름과 가격을 하나씩 묶어 출력하고 싶다고 해 보자. (두 리스트의 길이는 동일하다고 가정하자)
fruit_name_list = ['apple', 'banana', 'grape', 'durian', 'orange']
fruit_price_list = [5, 10, 20, 100, 8]
1. Naive indexing (worst solution)
C++에서 막 Python으로 넘어왔다면, 아래와 같은 인덱싱 방식으로 두 리스트의 값을 가져오는 방식이 본인 손에 더 자연스러울 것이다.
for fruit_index in range(len(fruit_name_list)):
fruit_name = fruit_name_list[fruit_index]
fruit_price = fruit_price_list[fruit_index]
print(f"Name: {fruit_name} \t Price: {fruit_price}")
위 코드는 잘 작동하지만.. 리스트의 길이를 구해 인덱스를 생성하고, 두 리스트 각각을 인덱싱 하는 작업으로 인해 전반적으로 코드의 길이가 길어진다.
2. Enumerate
다른 방법으로는 enumerate 기능을 사용할 수 있다. 아래 코드는 과일 리스트의 내용물을 변수에 바로 대입해 가져오면서, 함께 언패킹 하고 있는 인덱스 fruit_index를 사용해 가격 값을 불러오고 있다.
for fruit_index, fruit_name in enumerate(fruit_name_list):
fruit_price = fruit_price_list[fruit_index]
print(f"Name: {fruit_name} \t Price: {fruit_price}")
코드가 조금 더 간결해졌다. 하지만 여전히 추가적인 인덱싱을 사용해 fruit_price를 가져오고 있으며, fruit_index는 fruit_price를 인덱싱 하는 데에만 쓰이기 때문에 코드를 읽기 조금 불편하다는 점이 걸린다.
3. Zip (best solution)
Python의 zip 내장 함수를 이용하면 위 작업을 좀 더 단순한 코드로 작성할 수 있다. zip 함수는 여러 이터레이터 (예: 리스트) 를 묶어 각 이터레이터의 다음 값을 튜플 형태로 반환한다.
for fruit_name, fruit_price in zip(fruit_name_list, fruit_price_list):
print(f"Name: {fruit_name} \t Price: {fruit_price}")
fruit_list와 fruit_price_list 안의 값들이 zip을 통해 튜플로 묶여 반환되고 있으며, 추가적인 인덱싱 없이 바로 변수에 대입되고 있다. 위의 예시들에 비해 훨씬 간결하고 읽기 쉽다.
주의할 점은, 서로 길이가 다른 이터레이터를 zip으로 묶는다면 전체적인 길이는 더 짧은 이터레이터에 맞춰지게 된다는 것이다. 만약 더 긴 리스트의 길이에 맞춰 zip을 적용하고 싶다면, itertools.zip_longest를 사용하면 된다!
Source Code
fruit_name_list = ['apple', 'banana', 'grape', 'durian', 'orange']
fruit_price_list = [5, 10, 20, 100, 8]
# Method 1
print("< Method 1 >")
for fruit_index in range(len(fruit_name_list)):
fruit_name = fruit_name_list[fruit_index]
fruit_price = fruit_price_list[fruit_index]
print(f"Name: {fruit_name} \t Price: {fruit_price}")
# Method 2
print("< Method 2 >")
for fruit_index, fruit_name in enumerate(fruit_name_list):
fruit_price = fruit_price_list[fruit_index]
print(f"Name: {fruit_name} \t Price: {fruit_price}")
# Method 3
print("< Method 3 >")
for fruit_name, fruit_price in zip(fruit_name_list, fruit_price_list):
print(f"Name: {fruit_name} \t Price: {fruit_price}")