안녕하세요. 개발 중인 정주입니다.
오늘은 "프로그래머스(Lv.2) - [3차] 파일명 정렬" 문제를 풀었습니다.
Github
문제 링크
풀이
이번 문제는 문자열 처리와 정렬에 관한 문제입니다.
1. 파일명을 적절히 나눕니다.
파일명은 head, number로 나눠줍니다.
tail은 정렬에 쓰이지 않기 때문에 필요 없습니다.
파일명에서 숫자가 처음 나오는 부분 직전까지는 head 이고 숫자부터 숫자가 끝나는 부분까지가 number입니다.
저는 여기에서 실수해서 약간 헤맸습니다.
파일명을 한 글자 한 글자 체크를 했는데 isNumber를 사용해서 숫자면 숫자로, 아니면 head(혹은 tail)로 처리했습니다.
이렇게 분류를 하면 tail쪽에 있는 숫자도 number에 포함되어 잘못된 결과가 나옵니다.
이럴 경우 숫자가 끝나면 반복을 break 하는 등의 처리를 해줘야 합니다.
1-1. 리팩토링
저는 다른 분의 풀이를 보고 리팩토링을 했습니다.
prefix(while:)과 drop(while:)을 이용했는데요.
prefix를 이용해 숫자 이전까지 잘라 head를 구했습니다.
drop은 number를 구할 때 사용했는데요.
파일명에서 숫자 이전까지를 drop 하고 prefix를 이용해 숫자가 끝나는 부분까지 구했습니다.
이렇게 단 두 줄로 head와 number를 구할 수 있었습니다.
var head = file.prefix { !$0.isNumber }.lowercased()
var number = file.drop { !$0.isNumber }.prefix(while: { $0.isNumber })
2. 정렬합니다.
문제에 나온 규칙대로 정렬을 해줍니다.
처음에는 특수 기호를 따로 처리해주었는데요.
따로 처리를 안 해도 잘 정렬해주더라고요. Swift sort 최고!
후기
몰랐던 prefix(while:)과 drop(while:)을 새로 배웠습니다.
둘 다 O(n)이라 이 메소드들을 중첩해서 사용하는 것은 시간복잡도 면에서 손해지만...
코드가 유의미하게 짧아지고 가독성도 좋아져서 기억해두고 유용하게 써야겠습니다.
감사합니다!
전체 코드
import Foundation
struct Word {
var head: String
var number: String
var index: Int
}
func makeWord(_ file: String, index: Int) -> Word {
var head = file.prefix { !$0.isNumber }.lowercased()
var number = file.drop { !$0.isNumber }.prefix(while: { $0.isNumber })
// print("head: \(head) / number: \(number)")
return Word(head: head, number: String(number), index: index)
}
func isAFrontB(_ a: Word, _ b: Word) -> Bool {
let aNum = Int(a.number)!, bNum = Int(b.number)!
if a.head != b.head { return a.head < b.head }
if aNum != bNum { return aNum < bNum }
return a.index < b.index
}
func solution(_ files:[String]) -> [String] {
var words: [Word] = []
for (i, file) in files.enumerated() {
words.append(makeWord(file, index: i))
}
words.sort { isAFrontB($0, $1) }
print("words: \(words)")
let result: [String] = words.map { files[$0.index] }
print("result: \(result)")
return result
}
아직은 초보 개발자입니다.
더 효율적인 코드 훈수 환영합니다!
공감과 댓글 부탁드립니다.