프로그래머스
코딩테스트 연습 > 2018 KAKAO BLIND RECRUITMENT > [3차] 파일명 정렬
소스 파일 저장소에 저장된 파일명은 100 글자 이내로, 영문 대소문자, 숫자, 공백(" "), 마침표("."), 빼기 부호("-")만으로 이루어져 있다. 파일명은 영문자로 시작하며, 숫자를 하나 이상 포함하고 있다.
파일명은 크게 HEAD, NUMBER, TAIL의 세 부분으로 구성된다.
파일명 HEAD NUMBER TAIL foo9.txt foo 9 .txt foo010bar020.zip foo 010 bar020.zip F-15 F- 15 (빈 문자열)
파일명을 세 부분으로 나눈 후, 다음 기준에 따라 파일명을 정렬한다.
파일명은 우선 HEAD 부분을 기준으로 사전 순으로 정렬한다.
이때, 문자열 비교 시 대소문자 구분을 하지 않는다. MUZI와 muzi, MuZi는 정렬 시에 같은 순서로 취급된다.
파일명의 HEAD 부분이 대소문자 차이 외에는 같을 경우, NUMBER의 숫자 순으로 정렬한다. 9 < 10 < 0011 < 012 < 13 < 014 순으로 정렬된다.
숫자 앞의 0은 무시되며, 012와 12는 정렬 시에 같은 같은 값으로 처리된다.
두 파일의 HEAD 부분과, NUMBER의 숫자도 같을 경우, 원래 입력에 주어진 순서를 유지한다. MUZI01.zip과 muzi1.png가 입력으로 들어오면, 정렬 후에도 입력 시 주어진 두 파일의 순서가 바뀌어서는 안 된다.
입력으로 배열 files가 주어진다. files는 1000 개 이하의 파일명을 포함하는 문자열 배열이다.
각 파일명은 100 글자 이하 길이로, 영문 대소문자, 숫자, 공백(" "), 마침표("."), 빼기 부호("-")만으로 이루어져 있다. 파일명은 영문자로 시작하며, 숫자를 하나 이상 포함하고 있다.
중복된 파일명은 없으나, 대소문자나 숫자 앞부분의 0 차이가 있는 경우는 함께 주어질 수 있다. (muzi1.txt, MUZI1.txt, muzi001.txt, muzi1.TXT는 함께 입력으로 주어질 수 있다.)
입력: ["img12.png", "img10.png", "img02.png", "img1.png", "IMG01.GIF", "img2.JPG"]
출력: ["img1.png", "IMG01.GIF", "img02.png", "img2.JPG", "img10.png", "img12.png"]
입력: ["F-5 Freedom Fighter", "B-50 Superfortress", "A-10 Thunderbolt II", "F-14 Tomcat"]
출력: ["A-10 Thunderbolt II", "B-50 Superfortress", "F-5 Freedom Fighter", "F-14 Tomcat"]
python 에 있는 re 모듈을 사용한다면 쉽게 해결할 수 있을 것 같아 사용했다.
solution.py
import re
def sort_key(x):
head = x[1].lower()
number = int(x[2])
return(head, number) #헤더와 숫자를 기준으로 정렬
def solution(files):
fHead_num = []
for idx in range(len(files)):
f = files[idx]
match = re.search(r'\d{1,5}', f) #정규식으로 숫자 찾기
start, end = match.span() # 매칭된 숫자의 시작과 끝 인덱스
fHead_num.append([idx, f[:start], f[start:end]]) # (인덱스, 헤드, 숫자) 저장
fHead_num.sort(key=sort_key)
answer = [files[idx] for idx, _, _ in fHead_num]
return answer
re.search() 함수
re.search()는 문자열에서 주어진 패턴(여기선 r'\d{1,5}', 즉 1~5자리의 숫자)을 찾아 처음 일치하는 부분을 반환. 이 함수는 매칭된 부분이 있으면 Match 객체를 반환하고, 없으면 None을 반환합니다.
Match 객체
match는 re.search()가 반환한 Match 객체입니다. 이 객체에는 매칭된 정보(예: 패턴이 시작하고 끝나는 위치, 매칭된 문자열)가 저장되어 있습니다.
match.span()은 매칭된 패턴의 시작과 끝 인덱스를 반환합니다. 이 코드에서는 매칭된 숫자의 시작과 끝 위치를 얻어 파일명에서 헤드와 숫자를 분리합니다.
re.Match 객체의 주요 메서드
span(): 매칭된 패턴의 시작과 끝 인덱스를 튜플로 반환.
group(): 매칭된 문자열을 반환.
start(): 매칭된 패턴의 시작 인덱스.
end(): 매칭된 패턴의 끝 인덱스.
import re
def solution(files):
def key_function(fn):
head,number,tail = re.match(r'([a-z-. ]+)(\d{,5})(.*)',fn).groups()
return [head,int(number)]
return sorted(files, key = lambda x: key_function(x.lower()))
sort() / sorted()
sort 함수는 리스트명.sort( ) 형식으로 "리스트형의 메소드"이며 리스트 원본값을 직접 수정
sorted 함수는 sorted( 리스트명 ) 형식으로 "내장 함수"이며 리스트 원본 값은 그대로이고 정렬 값을 반환
lambda 사용
2.1 코드 길이 단축
2.2 input을 함수로 받아서 리스트 생성 하나 줄여줌
re 사용법
3.1 re.match().groups()
3.2 문자열 + 숫자 (5개) + 전부