<문제 1> Number Stack

반복 구문을 이용해 다음 화면과 같이 출력하시오. 

1
1 2
1 2 3
1 2 3 4
1 2 3 4 5

< 나의 삽질 >


PyCharm에서 아래와 같은 코드를 실행했을 때


1
2
3
i = 1
for i in range(1, 6):
    print(range(1, i+1))  

[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5]

위와 같은 결과가 출력된다. 리스트 상태인 이 출력값을 어떻게 int로 바꿀지 고민하는 와중에 
또 다른 문제에 봉착했다. 

같은 코드를 Jupyter Notebook에서 실행했을 때 

range(1, 2)
range(1, 3)
range(1, 4)
range(1, 5)
range(1, 6)



위와 같은 결과를 돌려주기 때문이다. 

흠 
왜지 

머리가 아파 그냥 모범 코드를 봤다. 

< 모범 코드 > 


1
2
3
4
for x in range(1,6):
    for y in range(1, x + 1):
        print(y, end=' ')
    print()   

아, 'i = 1' 을 따로 지정해줄 필요가 없구나. 
그리고 print에서 계속 헤맸던 부분은 인자 end = ''  로 해결할 수 있다. 



참고 : help(print) 
help( ) 함수의 매개변수 end= 의 디폴트는 개행 명령어인 '\n'

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
'''Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.'''




<문제 2> 3-digit numbers

다음과 같은 양의 정수들이 들어 있는 리스트 a에 대하여, 세 자리 정수만 골라내어 별도의 리스트 b에 저장하시오. 

a = [55, 123, 7777, 850, 72, 13579, 444, 2020, 9] 

print(b)
>>> [123, 850, 444] 

< 내 코드 > 

1
2
3
4
5
6
a = [55, 123, 7777, 850, 72, 13579, 444, 2020, 9]
b = []
for i in a:
    if i > 100 and i < 1000 :
        b.append(i)
print(b)

< 모범 코드 > 

(1) 

1
2
3
4
5
a = [55, 123, 7777, 850, 72, 13579, 444, 2020, 9]
b = []
for i in a:
    if 100 <= i <= 999:
        b.append(i)

4행에서 i 범위 설정을 좀 더 깔끔하게 해준 것 빼고는 비슷하다. 


(2) list comprehension으로 한 줄 코드로 끝낼 수도 있다.


1
b = [i for i in a if 100 <= i <= 999] 

아 콤팩트하다. 





<문제 3> Palindrome

회문(palindrome)이란 거꾸로 읽어도 원래 내용과 동일한 형태의 단어를 뜻한다. 사용자로부터 입력 받은 텍스트가 회문인지 아닌지 검사하는 프로그램을 작성하시오. (대소문자를 구분한다.)



< 내 코드 > 



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
str = input('텍스트를 입력하세요 : ')
str_len = len(str)
reverse_str = ''
for i in range(str_len):
    reverse_str += str[::-1] 
    test_txt = reverse_str[:str_len]

if test_txt == str:
    print(True)
else : 
    print(False)

문제에 (대소문자를 구분한다.) 라는 문구가 있어 대소문자 구문을 잠시 고민했는데 어차피 파이썬이 알아서 대소문자를 구분해주므로 신경 쓸 필요 없다. 낚일 뻔 

문자열(str) 순서를 뒤바꾸는 데서 막히기 쉬운데 슬라이싱 [::-1] 를 이용해, 처음부터 끝까지 -1칸씩 돌려주면 6행에서와 같이 한 줄로 구현 가능하다.  

위 코드는 제대로 실행되긴 한다. 


< 모범 코드 >  

(1)  

1
2
3
4
5
s = input("텍스트를 입력하세요 : ")
if s == s[::-1]:
    print(True)
else:
    print(False)

나는 코드 10줄로 구현한 걸 5줄에 구현했다. 
나는 정말 비효율적 인간인건가라는 자괴감이 들지만, 다음엔 잘 하겠지 뭐 -   

(2) 또는 해당 기능을 더 명확하게 드러내기 위해 함수로 정의할 수 있다. 



1
2
3
4
def is_palin(s):
    return s == s[::-1]
s = input("텍스트를 입력하세요 : ")
print(is_palin(s))

명쾌 😀


<문제 4> What is your last name?

다음과 같이 학생들의 이름이 나열되어 있는 문자열 names에 대하여 사용자가 입력한 성(last_name)에 해당하는 학생은 몇 명인지 출력하시오. 

names = "고은비, 김철수, 김은비, 김태상, 변수정, 양준하, 이재석, 임하나, 정우성, 정석원, 최나래, 최슬기, 한고은, 황비호"  



< 내 코드 > 


1
2
3
4
5
6
7
8
9
names = "고은비, 김철수, 김은비, 김태상, 변수정, 양준하, 이재석, 임하나, 정우성, 정석원, 최나래, 최슬기, 한고은, 황비호"
last_names = []

for name in names:
    last_names += name[i][0]

last_name = input('찾으려는 성을 입력하세요 : ')
cnt = last_names.count(last_name)
print("{}씨는 총 {}명 입니다.".format(last_name, cnt))


위 코드는 성공적으로 실행된다. 
위 코드에서는 리스트에 포함된 x의 개수를 세는 .count( ) 함수를 사용했다. 


< 모범 코드 > 

(1) 

1
2
3
4
5
6
7
8
9
last_name = input("찾으려는 성을 입력하세요 : ")
full_names_list = names.split(",")
number_of_students = 0

for s in full_names_list:
    if s[0] == last_name:
        number_of_students += 1

print(last_name + "씨는 총 " + str(number_of_students) + "명입니다.")


나는 입력받은 성씨를 가진 사람 수를 세기 위해 last_name 리스트를 만들고, 리스트 내 항목들을 .count( ) 함수로 구했는데, 위 코드에선 number_of_students 변수를 만들고 for문을 돌려 변수를 1 씩 추가해나갔다. 이 방법이 다 간소하다.


(2) 더 간소하게 구현하는 코드도 있다.


1
2
3
last_name = input("찾으려는 성을 입력하세요 : ")

print(last_name + "씨는 총 " + str(len([s for s in names.split(",") if s[0] == last_name])) + "명입니다.")


문제를 풀며 든 궁금증 :

위 경우엔 요행히도 성 한 글자, 이름 두 글자로 이뤄진 이름들만 주어졌다. 그래서 성을 찾을 때 문자열 인덱스를 이용할 수 있었다. 그런데 만약 성이 두 글자라면? 혹은 영어 이름으로 같은 문제를 풀어야 한다면?
나중에 머리 맑을 때 생각해볼 것! 영어 이름의 경우 보통 성과 이름 사이에 띄어쓰기를 하니까 ' '를 기준으로 나눠 판단할 수 있을 것 같긴한데.... 

만약 이름 리스트에 한글 이름과 영어 이름이 섞여 있다면 어떻게 풀지? 


< 문제 5 > A set of counters 

사용자가 입력한 문자열에 대하여, 다음 화면과 같이 문자열 내의 각 문자들이 몇 번씩 나왔는지 횟수를 세어서 출력하시오. 



< 내 코드 - 미완 > 


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
string = input('데이터를 입력하세요: ')
list = []

for cha in string:
    list.append(cha)
dic = {}
for i in range(0, len(list)):
    cnt = list.count(list[i])
    dic[list[i]] = cnt 

dic.items()

어찌어찌 위와 같은 코드를 짰지만,

>>>

데이터를 입력하세요: apple_and_banana


dict_items([('a', 5), ('p', 2), ('l', 1), ('e', 1), ('_', 2), ('n', 3), ('d', 1), ('b', 1)])

<<< 

이렇게 dict_items 구조로 출력된다. 이걸 어떻게 문제에서 요구하는 출력 값으로 정제하지? 
머리가 안 돌아간다. 

머리가 너무 아프니까 그냥 편한 길을 택하자.



< 모범 코드 > 


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
s = input("데이터를 입력하세요 : ")
d = dict()

for c in s:
    if c not in d:
        d[c] = 1
    else:
        d[c] += 1

for c in d:
    print(c, "\t", d[c])

되게 간단하네 ^^;  

< collections 모듈을 사용한 코드 > 


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from collections import Counter
s = input('데이터를 입력하세요 :')
cnt_dict = Counter(s)
keys = []
for i in cnt_dict:
    keys.append(i)
values = []
for i in keys:
    values.append(cnt_dict.get(i))

for i in range(len(keys)-1):
    print(keys[i],'    ', values[i])


흠... items를 사용해서 더 간단히 풀 수 있을 것 같은데.......흠.... 



참고 // dict( ) 함수