Notice
Recent Posts
Recent Comments
관리 메뉴

즐겁게, 코드

미세먼지 파이썬 팁 : enumerate 클래스로 for문 개선하기 본문

💬 언어/Python

미세먼지 파이썬 팁 : enumerate 클래스로 for문 개선하기

Chamming2 2022. 11. 25. 17:06

자바스크립트의 .forEach, .map 등 메서드를 활용하면 현재 순회중인 요소와 인덱스를 함께 얻을 수 있습니다.

const array = [a, b, c];
array.forEach((item, index) => {
  console.log(`item: ${item} / index: ${index}`);
}

// item: a / index : 0
// item: b / index : 1
// item: c / index : 2

이는 배열의 요소에 접근할 때 인덱스로 접근할 것이냐, 요소 자체에 접근할 것이냐를 고민하지 않게 해주어 코드 퀄리티와 생산성을 높여주기도 하는데요, 파이썬에서는 항상 이런 고민을 해야만 했습니다.

string = "Hello, World!"

# 순회중인 요소에 직접 접근할 것이냐
for char in string:
  print(char);
  
# 아니면 현재 loop index를 통해 접근할 것이냐
for index in range(len(string)):
  print(string[index]);

어느 쪽이든 코드를 작성하는 데에는 문제가 없지만, 인덱스와 요소를 함께 활용해야 하는 상황에서는 파이썬의 기본 for문을 멋지게 사용하기 어렵습니다.

string = "Hello, World!"
  
# 쿨하지 않은 부분 1. range(len(string)) 
for index in range(len(string)):
  print(index);
  
  # 쿨하지 않은 부분 2. string[index]
  print(string[index]);

파이썬에서도 자바스크립트처럼 루프를 돌 때마다 (요소, 인덱스) 의 튜플을 얻을 수 있는 방법이 있다면 얼마나 좋을까요?

오늘 다룰 enumerate 클래스와 함께라면, 이제 for문을 멋지게 개선할 수 있게 됩니다.

enumerate 클래스

enumerate의 설명과 구현입니다.

class enumerate(Iterator[tuple[int, _T]], Generic[_T]):
    def __init__(self, iterable: Iterable[_T], start: int = ...) -> None: ...
    def __iter__(self: Self) -> Self: ...
    def __next__(self) -> tuple[int, _T]: ...

보다시피 이터러블한 요소(Ex. 문자열, 배열, 튜플 등)을 생성자 인자로 받아 [인덱스, 현재 순회중인 요소] 의 튜플을 반환하고 있는데요, 한번 실제로 사용해 보겠습니다.

string = "hello, world"
for index, item in enumerate(string):
    print("index: {} / item: {}".format(index, item))
    
# index: 0 / item: h
# index: 1 / item: e
# index: 2 / item: l
# index: 3 / item: l
# index: 4 / item: o
# index: 5 / item: ,
# index: 6 / item:  
# index: 7 / item: w
# index: 8 / item: o
# index: 9 / item: r
# index: 10 / item: l
# index: 11 / item: d

루프를 순회하면서, 정말 간단히 인덱스와 현재 요소를 얻어내고 있는 모습입니다!

enumerate의 성능

파이썬이 사랑받는 곳 중 하나인 코딩 테스트에서는 무엇보다 성능이 중요한데요, 결론부터 이야기하자면 enumerate 는 메서드가 아니기 때문에 함수의 I/O를 일으키지 않고, 이터레이션 프로토콜만을 수정하기 때문에 시간 복잡도는 O(1) 이 됩니다.

참조 : https://stackoverflow.com/questions/31127594/complexity-of-enumerate
  • 1 ~ 1000000을 enumerate와 함께 순회할 때
import time
import datetime

start = time.time()

a = [0] * 1000000
for index, item in enumerate(a):
    print("index: {} / item: {}".format(index, item))

end = time.time()


sec = (end - start)
result = datetime.timedelta(seconds=sec)
print(result)

result_list = str(datetime.timedelta(seconds=sec)).split(".")
print(result_list[0])
  • 1 ~ 1000000을 enumerate 없이 순회할 때
import time
import datetime

start = time.time()

a = [0] * 1000000
for index in range(len(a)):
    print("index: {} / item: {}".format(index, a[index]))

end = time.time()


sec = (end - start)
result = datetime.timedelta(seconds=sec)
print(result)

result_list = str(datetime.timedelta(seconds=sec)).split(".")
print(result_list[0])
  • 결과 (좌 : with enumerate / 우 : without enumerate)

with enumerate (6s) > without enumerate (7s) = enumerate의 사용은 성능에 악영향을 미치지 않는다.

이처럼 enumerate가 코드 실행에도 나쁜 영향을 미치지 않는다는 것을 확인할 수 있었는데요, 이처럼 간단한 내장 클래스만으로도 코드 퀄리티를 개선할 수 있는 방법이 있다는 것을 살짝 알아 두시면 좋을 것 같습니다 🙂

반응형
Comments
소소한 팁 : 광고를 눌러주시면, 제가 뮤지컬을 마음껏 보러다닐 수 있어요!
와!! 바로 눌러야겠네요! 😆