- 2시간 안 쪽으로 푼 것 같다.
내 최초 풀이
# 튜플
def solution(s):
answer = []
given_list_without_braket = list(map(lambda x: x.split(","), s[2:-2].split("},{")))
number_count_dict = dict()
for element in given_list_without_braket:
for number in element:
if number in number_count_dict:
number_count_dict[number] = number_count_dict[number] + 1
else:
number_count_dict[number] = 1
for item in sorted(
list(number_count_dict.items()), key=lambda x: x[1], reverse=True
):
answer.append(int(item[0]))
return answer
print(solution("{{2},{2,1},{2,1,3},{2,1,3,4}}"))
print(solution("{{1,2,3},{2,1},{1,2,4,3},{2}}"))
print(solution("{{20,111},{111}}"))
print(solution("{{123}}"))
print(solution("{{4,2,3},{3},{2,3,4,1},{2,3}}"))
- 많이 출현한 숫자 순서대로 튜플이 만들어진다는 것을 몰라서 처음에 많이 혼란스러웠다. 지금도 왜 그런지 모른다. 모든 튜플이 아니라, 이 문제에서 나온 튜플이 이런 성질을 가지고 있다는 것이겠지.
- 문자열을 파싱한다.
- 숫자마다 나온 개수를 딕셔너리(숫자 : 나온 개수)에 넣는다.
- 딕셔너리를 튜플의 리스트로 바꾼다.
- 리스트를 튜플의 두번째 인자 기준으로 내림차 정렬한다.
- 리스트의 튜플 첫번째 인자를 순서대로 모아 리스트(답)를 만든다.
다른 사람 풀이
Counter, re 모듈을 활용한 풀이, 가장 많이 나온 숫자가 튜플에 우선한다는 원칙으로 풀이
def solution(s): s = Counter(re.findall('\d+', s)) return list(map(int, [k for k, v in sorted(s.items(), key=lambda x: x[1], reverse=True)])) import re from collections import Counter
코드의 짧음을 과시하기라도 하듯 solution을 위로 올려버린 발상도 좋지만, 파이썬 컨벤션에 맞춰 보기 쉽게 바꿔보자.
Counter 클래스의 most_common() 메서드를 사용하면 위의 lambda를 활용한 정렬을 생략할 수 있다.
코드는 좀 길어지겠지만 내가 생각하기에 더 읽기 좋아 보이게 리팩토링한다면 다음과 같다.
import re from collections import Counter def solution(s): numbers_sorted_by_frequency = Counter(re.findall("\d+", s)).most_common() answer = [] for key, value in numbers_sorted_by_frequency: answer.append(int(key)) return answer
내가 수정한 최적 답안은 다음과 같다.
import re from collections import Counter def solution(s): numbers_sorted_by_frequency = Counter(re.findall("\d+", s)).most_common() return [int(key) for key, value in numbers_sorted_by_frequency]
lstrip, rstrip 사용해 파싱, 작은 크기의 집합의 원소가 튜플에 우선한다는 원칙으로 풀이
def solution(s): answer = [] s1 = s.lstrip('{').rstrip('}').split('},{') new_s = [] for i in s1: new_s.append(i.split(',')) new_s.sort(key = len) for i in new_s: for j in range(len(i)): if int(i[j]) not in answer: answer.append(int(i[j])) return answer
문자열 파싱 방법은 그렇게 놀랄 게 아니다.
정답 리스트에 원소를 넣는 기준이 집합 크기가 작은 것의 요소를 검사하고, 등장한 순서대로 넣는다는 것이다.
의문 → 같은 숫자가 등장하면 answer에 들어가지 않는 것 아닌가?
print(solution("{{2},{2,3},{2,3,1},{2,3,1,2}}")) # [2, 3, 1]
- 내가 생각하는 튜플 만드는 방식이 틀렸거나, 아니면 프로그래머스 테스트케이스에 중복 원소가 등장하는 경우가 없는 것 같다.
새로 안 것
sort(key=len) → 요소의 길이에 따라 정렬함
eval() → 쌍따옴표 안에 넣은 것을 바로 실행하여 결과를 출력함. 위험성 때문에 안 쓰는 게 좋다.
map의 반환 결과는 iterator, list로 바꿔주어야 일반적으로 사용할 수 있다.
re 모듈 → 정규표현식과 그 관련된 함수를 알아두면 문자열 파싱에 매우 유용하다. 근데 보기에 매우 어렵다.
collections 의 Counter 모듈...이 아니라 collections 모듈에 Counter 클래스네? 모듈과 클래스의 차이가 뭐지??
- Counter 클래스(추가 설명) → 어떤 요소가 몇 번 나왔는지 세어서 dict로 만들어준다.
- 클래스의 메서드로 most_common()이 있는데 가장 많이 나온 순서대로 dict의 item을 정렬해서 리스트로 반환해준다!
- Counter 클래스(추가 설명) → 어떤 요소가 몇 번 나왔는지 세어서 dict로 만들어준다.
문자열 거꾸로 출력할 때
string[::-1]
먼저 두번째 콜론 뒤가 -1인지 알고, 인덱싱할 때 '거꾸로' 탐색한다.
>>> a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> a[:3] [0, 1, 2] >>> a[:2:-1] [9, 8, 7, 6, 5, 4, 3] >>> a[3:0:-1] [3, 2, 1] >>> a[3:2:-1] [3] >>> a[9:2:-1] [9, 8, 7, 6, 5, 4, 3]
'프로그래밍-학습기록 > 코딩테스트' 카테고리의 다른 글
프로그래머스 | python | level 2 | 올바른 괄호 (0) | 2020.12.22 |
---|---|
프로그래머스 | python | level 2 | 다리를 지나는 트럭 (0) | 2020.12.22 |
우아한 테크코스 코딩테스트 + 프리코스 회고 (0) | 2020.12.21 |
백준 온라인 저지 | 4673 | 함수: 셀프 넘버 (0) | 2020.07.31 |
백준 온라인 저지 | 4344 | 배열: 평균은 넘겠지 (0) | 2020.07.29 |