ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [프로그래머스 2단계] 알고리즘 25. 이상한 문자 만들기
    레거시/레거시-알고리즘(3) 2018. 4. 11. 11:17
    반응형

    문제 출처는 프로그래머스 알고리즘 연습 에서 볼 수 있습니다!(https://programmers.co.kr/learn/challenges)


    알고리즘 25. 이상한 문자 만들기

    toWeirdCase함수는 문자열 s를 매개변수로 입력받습니다. 문자열 s에 각 단어의 짝수번째 인덱스 문자는 대문자로, 홀수번째 인덱스 문자는 소문자로 바꾼 문자열을 리턴하도록 함수를 완성하세요. 예를 들어 s가 try hello world라면 첫 번째 단어는 TrY, 두 번째 단어는 HeLlO, 세 번째 단어는 WoRlD로 바꿔 TrY HeLlO WoRlD를 리턴하면 됩니다. 주의 문자열 전체의 짝/홀수 인덱스가 아니라, 단어(공백을 기준)별로 짝/홀수 인덱스를 판단합니다.

    def toWeirdCase(s):
    # 함수를 완성하세요
    return ''

    # 아래는 테스트로 출력해 보기 위한 코드입니다.
    print("결과 : {}".format(toWeirdCase("try hello world")));


    풀이 :

    이번 문제는 주어진 문자열을 공백으로 쪼갠후에 단어별로 자릿수가 홀/짝에 따라 대/소문자로 변경하는 문제이다. 알고리즘은 다음과 같다.

    1. 문자열을 공백으로 쪼개준다. split(" ")
    2. 쪼갠 단어마다 단어의 자릿수가 홀/짝에 따라 문자들을 대/소문자로 바꿔준다.

    알고리즘 2번 단어로 쪼갠 후 단어의 자릿수마다 문자들을 바꿔주는 방법은 여러가지가 있다. 필자는 2가지의 방법을 제시한다. 먼저 제일 쉬운 문자열 슬라이싱 방법이다. 여기서 알아둘 점은 파이썬에서 문자열은 상수이므로 인덱스로 접근한들 변경이 불가능하다. 예를 들어 다음과 같이 코딩이 불가능하다.


    word = 'try'

    word[1] = word[1].upper()  # tRy?


    이런 효과를 내려면, 다음과 같이 문자열 자체를 슬라이싱해서 붙여주는 방식이 있다.


    word = word[:1] + word[1].upper() + word[1+1:]


    예는 두번째 원소를 바꾸려고(인덱스 기준으로 하면 index = 1인 위치) 했을 때이지만 이를 일반화해서 코드로 나타내면 다음과 같다.


    word = word[:index] + word[index] 문자 변환 + word[index+1:] 


    프로그래밍을 아는 사람이라면 index가 문자열 끝이라면 인덱스 에러가 날텐데 어떡합니까라고 물을 수 있는데 걱정마시라. 파이썬은 그런 문자열 인덱싱에 대한 처리를 해놓았다. 만약 마지막 문자라면 빈 문자열을 반환시켜준다. 따라서 위의 코드는 해당 인덱스에 개발자가 원하는 문자로 바꿔칠 수가 있다. 이제 그렇다면 단어마다 각 단어를 순회하여 자릿수마다 홀수라면 대문자를 짝수라면 소문자로 바꿔주면된다. 이는 다음과 같이 나타낼 수 있다.


    for index in range(0, len(word)):

    word = word[:index] + (word[index].lower() if index % 2 else word[index].upper()) + word[index+1:]

     

    그러나 이 word가 바뀐다고 해서 문자열이 바뀌진 않는다. 그래서 나 같은 경우는 리스트에 바뀐 단어를 집어넣어서 바로 리스트를 문자열로 반환하려 한다. 이제 얼추 설명을 했으니 이제 코드 전문을 보면서 이해하자. 주석을 보면 쉽게 이해가 될 것이다.


    def toWeirdCase(s):
    word_list = []                        #바뀐 단어들을 저장할 리스트
    for word in s.split(" "):             #주어진 문자열을 공백 기준으로 단어를 쪼갠다
    for i in range(0, len(word)):     #각 단어를 순회하면서 자릿수가 홀/짝이면 대/소문자로 변경한다.
    word = word[:i] + (word[i].upper() if i % 2 == 0 else word[i].lower()) + word[i+1:]
    word_list.append(word)            #바뀐 단어를 리스트에 삽입한다.
    return " ".join(word_list)            #이제 리스트 요소마다 " " 공백을 붙여 문자열로 만들어 반환한다.


    이 방법 외에는 enumerate 함수를 사용하는 방법이 있다. 같은 알고리즘이지만 더 간단하게 표현할 수 있다. enumerate에 간단하게 설명하자면 'try'라는 문자열이 있다고 해보자 그렇다면 이렇게 사용할 수가 있다.


    for (i, x) in enumerate('try'):

    print(i, x)


    라고 하면 결과는 다음과 같다.


    0, 't'

    1, 'r'

    2, 'y'


    순회할 요소를 인덱스와 같이 사용하고 싶을 때 enumerate 함수를 쓴다는 것을 기억하자. 그렇다면 위의 코드는 enumerate와 if + for 컴프리헨션으로 다음과 같이 변경될 수 있다.


    def toWeirdCase(s):
    word_list = []
    for word in s.split(" "):
    word = "".join( x.lower() if i % 2 else x.upper() for i, x in enumerate(word) )
    word_list.append(word)
    return " ".join(word_list)


    먼저 이 다음 코드를 살펴보자.


    x.lower() if i % 2 else x.upper() for i, x in enumerate(word)


    이 부분은 단어를 순회 하면서 자릿수가 홀/짝 이라면 대/소문자로 바꾼 문자들의 리스트를 반환해준다. 그 후 "".join(list) 를 실행하면 해당 리스트들을 아무 공백 없이 붙여서 문자열로 만든다. 예를 들어 word = 'try'라면 다음과 같이 변환한다.


    'try' -> 

    "".join( 

    (0 , t) ->  i % 2 == 0   -> (0, T) -> 'T' 반환

    (1 , r) ->  i % 2 != 0    -> (1, r) -> 'r' 반환

    (2 , y) ->  i % 2 == 0   -> (2, Y) -> 'Y' 반환

    ) ->

    "".join(['T', 'r', 'Y']) -> 

    'Try'


    이제 enumerate()를 활용한 단어 바꿔치기도 알아보았다. 위의 방법은 for 컴프리헨션을 통해 한줄로도 변경이 가능하다. 


    def toWeirdCase(s):
    return " ".join( "".join( x.lower() if i % 2 else x.upper() for i, x in enumerate(word) ) for word in s.split(" ") )


    이렇게 말이다. 그러나 이렇게 하면 솔직히 코드가 간단하고 멋있긴 하지만 보기 불편하다.(내 실력의 문제인가...) 파이썬은 가독성을 좋게 하자라는 철학을 갖고 있기 때문에 나는 위의 두 코드를 쓰라고 추천해주고 싶다. 이 문제와 비슷한 문제로 JadenCase 문자열 만들기가 있다. 이는 이 문제들을 충분히 이해했다면 금방 풀 수 있기 때문에 따로 올리진 않겠다. 한 번 풀어보라

Designed by Tistory.