분당아재의 솔직한 블로그

python checkio, All The Same 미션, 중복을 제거하는 비법 소개

파이썬 공부하기

파이썬을 게임하듯 문제를 풀며 공부하는 checkio.org의 Home Section 여섯번째 미션, All The Same 입니다. 

어렵게 머리를 써가며 문제를 풀었는데, 다른 분들이 푼 답안을 보고 깜짝 놀란 미션이기도 합니다. ㅎㅎ

입력으로 주어진 List가 모두 같으면 True, 하나라도 다르면 False를 return 하는 문제입니다.

all_the_same([1, 1, 1]) == True  # List의 값이 모두 1로 같으므로 True

all_the_same([1, 2, 1]) == False # List의 값이 1, 2로 다르므로 False

all_the_same(['a', 'a', 'a']] == True # List의 값이 모두 a로 같으므로 True


주어진 input은 짧지만 어떻게 풀까 고민하다가

List의 0번째 값과 1번째 값을 비교해서 같은지,

List의 1번째 값과 2번째 값을 비교해서 같은지,

이런 순서로 List의 인덱스를 하나씩 증가시키며 그 다음 값과 비교해서 

끝까지 값이 같으면 True를 return하고, 중간에 값이 바뀌면 False를 리턴하는 코드를 작성해서

미션을 풀었습니다. 


그러다가, 다른 답안을 보고 깜짝 놀랐네요.

바로 set()를 사용한 것입니다. 


set()의 특징 중 하나가 바로 중복을 허용하지 않고, 순서를 두지 않는 것인데요.

이 점을 이용해서 중복을 한방에 제거하는 것이였죠.


set([1, 1, 1]) 을 하면 중복을 제거한 {1}이 나옵니다. 

set([1, 2, 1, 2, 3]}을 하면 역시 중복된 값을 합친 후, {1, 2, 3}이 나옵니다.


이런 set()의 특징을 이용하니

all_the_same() 함수에서 return 문 하나로 문제해결이 되네요. 

return len(set(elements)) <= 1

1. set(elements) 문으로 elements 안의 중복을 모두 제거합니다. 

2. len()을 써서 set(elements)의 남은 값을 카운트 합니다.

   여기에서 len() 값이 1이면 elements의 값이 모두 중복이라는 뜻이고,

   len() 값이 2이상이면 elements의 값이 각각 다른 값을 가진 것이죠.

3. len(set(elements)) <=1 문장은 len() 값이 1보다 작은 지 큰 지를 비교하여 True, False를 남겨줍니다.

   따라서, elements의 값이 모두 중복이면 len()이 1이니까 True를 return하고,

   그렇지 않은 경우, False를 return 합니다. 


아주 간단하지만 중복을 제거하는 경우에 유용하게 사용할 수 있는 set() 함수네요.

꼭 기억해야겠습니다. 


파이썬 checkio, House Password 풀이와 해설

파이썬 공부하기

파이썬을 게임하듯 공부할 수 있는 checkio의 22번째 미션 House Password 입니다.

Elementary 섬의 모든 미션을 해결한 후 나오는 첫번째 미션이죠.


주어진 문자열이 암호의 조건에 맞으면 True, 틀리면 False를 리턴하는 미션입니다.

암호의 조건은 문자열의 길이가 10자 이상이고, 적어도 하나의 숫자, 대문자, 소문자를 포함하고 모두 ASCII 문자여야 합니다. 


checkio('A1213pokl') == False # 이 문자열은 길이가 10자 미만이라 False입니다.

checkio('bAse730onE') == True # 이 문자열은 암호 조건에 부합하므로 True입니다.

checkio('asasasasasasasaas') == False # 모두 소문자이므로 False

checkio('QWERTYqwerty') == False # 모두 대문자이므로 False

checkio('123456123456') == False # 모두 숫자이므로 False

checkio('QwErTy911poqqqq') == True # 암호 조건에 부합하므로 True 입니다.


제가 푼 해답의 소스를 하나씩 설명하면


def checkio(data: str) -> bool:

    #replace this for solution

    # 문자열 data의 길이를 내장함수 len을 써서 확인합니다. 

    # len(data) < 10 즉, 문자열의 길이가 10 미만이면, 바로 False를 리턴합니다. 

    if len(data) < 10:

        return False


    # data.isdigit()는 문자열이 모두 숫자로 구성되었는지 확인하는 부분입니다.

    # data가 "1234567890123"과 같이 길이는 10을 넘지만 모두 숫자로 구성되어 있기 때문에

    # 암호의 조건에 맞지 않습니다. 

    # data.isdigit() 가 True 즉, 모두 숫자로 구성된 문자열이면 False를 리턴합니다. 

    if data.isdigit() :

        return False


    # if data.isupper == data: 

    # 이 부분은 data를 모두 대문자(upper)로 변환한 결과가 처음 data와 같다면

    # 그렇다는 말은 data가 처음부터 모두 대문자란 말이죠. 이 경우엔 data에 소문자가 없으므로 False를 리턴

    if data.isupper == data :

        return False


    # if data.islower == data: 

    # 이 부분은 data를 모두 소문자(lower)로 변환한 결과가 처음 data와 같다면

    # 그렇다는 말은 data가 처음부터 모두 소문자란 말이죠. 이 경우엔 data에 대문자가 없으므로 False를 리턴

    if data.islower == data :

        return False


    # 이제.. 위 소스에서 네가지 조건이 걸러졌습니다.

    # 문자열의 길이가 10미만이거나, 문자열이 모두 숫자이거나 모두 대문자이거나 모두 소문자인 것은 

    # return False 되었습니다.

    # 이제 남은 문자열 data에 적어도 숫자 하나가 있는가?만 검사하면 됩니다. 

    # any 함수는 ()안에 들어간 인자 중에서 하나라도 True이면 True를 리턴합니다. 

    # c.isdigit() for c in data 

    # data에서 문자를 하나씩 꺼내어 c에 넣고, 이것은 isdigit()로 검사하여 숫자인가를 확인합니다.

    # data 중에서 하나라도 숫자가 있으면 True가 나오므로 결국 True를 리턴합니다. 

    return any(c.isdigit() for c in data)


처음 이 문제를 풀 때, data.isdigit() 부분을 빼고 왜 안되나 한참 고민했었네요.

모두 숫자일 때도 체크해야 합니다.