반복문이 리스트의 항목을 제대로 삭제하지 못합니다.

조회수 5104회

아래의 코드는 모든 모음 알파벳(aeiouAEIOU)을 문자열에서 제거해주는 함수 anti_vowel입니다. 제대로 동작할 거라 기대했는데, "Hey look Words!" 라는 샘플값을 입력값으로 주면 "Hy lk Words!"라고 반환됩니다. 즉, 마지막 'o'를 삭제하지 못하고 있는데, 왜 이러는 걸까요?

text = "Hey look Words!"

def anti_vowel(text):

    textlist = list(text)

    for char in textlist:
        if char.lower() in 'aeiou':
            textlist.remove(char)

    return "".join(textlist)

print anti_vowel(text)

1 답변

  • 좋아요

    0

    싫어요
    채택 취소하기

    반복문이 진행됨에 따라 리스트가 수정되면서 생기는 문제입니다. 아래의 코드와 같이 리스트의 복사본을 만들어 순회 중인 리스트에서 값을 제거하지 않도록 해보세요.

    for char in textlist[:]: #shallow copy of the list
        # etc
    

    좀더 명확하게 현재 문제를 파악해보고 싶으시다면 print char, textlist를 반복문의 시작부분에 삽입해보세요. 아마 리스트 좌측에 원본 문자열이 수직으로 나올거라 생각하셨겠지만, 사실 출력되는 값은 아래와 같습니다 :

    H ['H', 'e', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
    e ['H', 'e', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
      ['H', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!'] # !
    l ['H', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
    o ['H', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
    k ['H', 'y', ' ', 'l', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!'] # Problem!!
      ['H', 'y', ' ', 'l', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
    W ['H', 'y', ' ', 'l', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
    o ['H', 'y', ' ', 'l', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!'] 
    d ['H', 'y', ' ', 'l', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
    s ['H', 'y', ' ', 'l', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
    ! ['H', 'y', ' ', 'l', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
    Hy lk Words!
    

    왜 이러는걸까요? 파이썬의 for x in y 형태의 반복문은 사실 겉보기에 좀더 직관적으로 보일 뿐, 사실 일반적인 반복문처럼 리스트의 각 요소들을 인덱스로 순회합니다. 즉, 리스트를 순회하면서 리스트의 요소들을 제거하다보면, (위에 보이는 바와 같이) 스킵하고 지나가는 값들이 생기는 거죠. 이는 결국 "look"의 두번째 o를 놓치고 지나가는 결과를 만듭니다. 왜냐하면 이전 문자를 삭제하면서 두번째 o의 인덱스가 한칸 당겨지면서 이미 순회한 인덱스가 되기 때문입니다. 그 후에, "Words"o를 찾게 되면, 문자열의 가장 첫번째 o, 즉, 놓치고 지나간 o를 삭제하게 되는 것이죠.


    만들고자 하시는 코드는 아래와 같이 더 좋은 (더 깔끔한) 방법으로 작성하실 수 있습니다.

    def remove_vowels(text): # function names should start with verbs! :)
        return ''.join(ch for ch in text if ch.lower() not in 'aeiou')
    

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)