복잡하게 보이지만 결국 문자열을 다루는 단순한 문제 중에 하나입니다. 문제에 나온대로 그래도 구현해주면 됩니다. 참고로 parse 함수를 sort 안에서 실행하면 최대 NlogN회 실행하게 되므로 미리 파싱을 해서 N회만 실행되도록 합시다.
// 출력할 때 원래 String로 필요로 하므로 tuple에 같이 저장
typealias HeadNumber = (s: String, h: String, n: Int)
func solution(_ files:[String]) -> [String] {
// 주어진 문자열을 Head와 Number로 나누기
func parse(of f: String) -> HeadNumber {
let fArray = f.map { $0 }
var head = ""
var tail = ""
var tailStartIndex = 0
// 숫자가 나오지 않을 때까지가 Head
for i in 0..<fArray.count {
// 숫자가 나오면 숫자가 시작되는 index 저장하고 break
if fArray[i].isNumber { tailStartIndex = i; break }
head += String(fArray[i])
}
// 첫 번째 숫자부터 연속된 숫자가 Number
for i in tailStartIndex..<fArray.count {
// 숫자가 아닐 때 break
if !fArray[i].isNumber { break }
tail += String(fArray[i])
}
return (f, head.uppercased(), Int(tail)!)
}
// 정렬 메소드
func sort(_ f1: HeadNumber, _ f2: HeadNumber) -> Bool {
// head가 다르면 head 기준으로 정렬
if f1.h != f2.h {
return f1.h < f2.h
// head가 동일하면 number 기준으로 정렬
} else {
return f1.n < f2.n
}
}
// 파싱하고 정렬하고 다시 원본으로 바꾸어서 리턴
return files.map { parse(of: $0) }.sorted(by: { sort($0, $1) }).map { $0.s }
}
String 타입에 있는 prefix와 drop 메소드를 통해서 parse 함수 부분의 간결하게 해보겠습니다.
prefix(while: ) 메소드는 클로저 “(Character) → Bool”가 true를 반환하는 부분까지를 return 합니다. drop(while: ) 메소드는 반대로 클로저가 true를 반환하는 부분를 빼고 남은 부분을 return 합니다.
이 두 메소드를 활용하면 prefix를 통해 숫자가 아닌 부분까지를 잘라서 head를 구할 수 있습니다. number를 구할 때는 drop을 통해서 head 부분을 제거하고 남은 부분에서 다시 숫가인 부분까지만 잘라서 구하면 됩니다.
// 출력할 때 원래 String로 필요로 하므로 tuple에 같이 저장
typealias HeadNumber = (s: String, h: String, n: Int)
func solution(_ files:[String]) -> [String] {
// 주어진 문자열을 Head와 Number로 나누기
func parse(of f: String) -> HeadNumber {
let head = f.prefix { !$0.isNumber }
let number = f.drop { !$0.isNumber }.prefix { $0.isNumber }
return (f, String(head).uppercased(), Int(number)!)
}
// 정렬 메소드
func sort(_ f1: HeadNumber, _ f2: HeadNumber) -> Bool {
// head가 다르면 head 기준으로 정렬
if f1.h != f2.h {
return f1.h < f2.h
// head가 동일하면 number 기준으로 정렬
} else {
return f1.n < f2.n
}
}
// 파싱하고 정렬하고 다시 원본으로 바꾸어서 리턴
return files.map { parse(of: $0) }.sorted(by: { sort($0, $1) }).map { $0.s }
}