슈프림 블로그
[프로그래머스] 2018 카카오 블라인드 코딩테스트 - 파일명 정렬 (Swift 풀이) 본문
programmers.co.kr/learn/courses/30/lessons/17686?language=swift
문자열들을 특정 조건에 맞게 정렬하는 문제다.
문자열 구성
- head: 영문, 공백, 특수문자 ( . - ) 로 이루어짐
- number: 숫자로 이루어짐
- tail: 사실상 신경쓰지 않아도 되는 부분
정렬 조건은 다음과 같다.
- head 사전 순 (대소문자 구분 안함)
- number 오름차순 (문자열이 아닌, 숫자로)
- 입력 순
정규식
먼저 문자열 구성을 각각 쪼개기 위해 정규식을 사용했다!
막간 정규식 관련 포스팅 홍보 -> tngusmiso.tistory.com/62
head를 구하는 패턴 : [a-zA-Z\\s\\.\\-]*
- a-zA-Z : 알파벳
- \\s : 공백
- \\. : 온점
- \\- : 하이픈
- [] : 괄호 안의 문자 중 하나
- * : 앞에 나온 문자 패턴이 1글자 이상 나온다.
number를 구하는 패턴: [\\d]*
- \\d : 숫자
- [] : 괄호 안의 문자 중 하나
- * : 앞에 나온 문자 패턴이 1글자 이상 나온다.
head와 number의 범위를 각각 구해준다.
headRange와 numberRange를 강제 언랩핑 한 근거는!
guard문을 통해 result값이 도출되었다는 것은 head, number에 일치하는 부분이 반드시 있었다는 뜻이기 때문이다.
let pattern: String = "^(?<head>[a-zA-Z\\s\\.\\-]*)(?<number>[\\d]*)"
let regex = try? NSRegularExpression(pattern: pattern, options: [])
for i in 0..<files.count {
let file = files[i]
guard let result = regex?.firstMatch(in: file, options: [], range: NSRange(location: 0, length: file.count)) else { continue }
let headRange = Range(result.range(withName: "head"), in: file)!
let numberRange = Range(result.range(withName: "number"), in: file)!
...
}
파일명 정보를 담고 있는 구조체 만들기
파일명 문자열을 정렬하기 위해 필요한 정보는 head, number, 입력 순서이다.
이 정보들을 가지고 있도록 하기 위해 FilName 이라는 구조체를 만들어보았다!
head는 대소문자 구분을 하지 않기 때문에 .lowercased()를 붙여주었고,
number는 Int형으로 변환해주었다.
struct FileName: Comparable {
let name: String
let order: Int
let head: String
let number: Int?
init(_ name: String, order: Int, headRange: Range<String.Index>, numberRange: Range<String.Index>) {
self.name = name
self.order = order
self.head = String(name[headRange]).lowercased()
self.number = Int(name[numberRange])
}
}
FileName 배열 만들기
아까 files를 순서대로 탐색하던 for문으로 돌아가서!
answer 배열에 FileName 객체들을 생성하여 넣어준다.
var answer: [FileName] = []
for i in 0..<files.count {
let file = files[i]
...
answer.append(file, order: i, headRange: headRange, numberRange: numberRange)
}
정렬하기
answer를 sorted() 함수로 정렬하기 위해서는
FileName 구조체가 Comparable 프로토콜을 준수해야 한다.
Comparable 프로토콜을 준수하기 위해서는 < 연산자를 정의해줘야 한다.
head끼리 같으면 number를 비교하고, number끼리 같으면 order를 비교하는 방식이다.
struct FileName: Comparable {
...
static func < (lFile: FileName, rFile: FileName) -> Bool {
guard lFile.head == rFile.head else {
return lFile.head < rFile.head
}
if let lNumber = lFile.number, let rNumber = rFile.number {
guard lNumber == rNumber else {
return lNumber < rNumber
}
}
return lFile.order < rFile.order
}
}
그리고 answer를 sorted 해준다.
그렇게 나온 결과값은 String 배열이 아니라 FileName 배열이므로 map을 통해 변환해주면 된다.
return answer.sorted().map { $0.name }
'코딩테스트' 카테고리의 다른 글
[프로그래머스] 2018 카카오 블라인드 코딩테스트 - 뉴스 클러스터링 (Swift 풀이) (0) | 2021.04.20 |
---|---|
[프로그래머스] 하노이의 탑 (Swift 풀이) (0) | 2021.04.16 |
[프로그래머스] 탐욕법(Greedy) - 큰 수 만들기 (Swift 풀이) (1) | 2021.01.10 |
[프로그래머스] 월간코드챌린지1 - 삼각 달팽이 (Swift 풀이) (0) | 2021.01.04 |
[프로그래머스] 탐욕법(Greedy) - 체육복 (Swift 풀이) (0) | 2020.10.29 |