(Swift) Programmers 파일명 정렬

SteadySlower·2023년 1월 24일
0

Coding Test

목록 보기
215/305

코딩테스트 연습 - [3차] 파일명 정렬

문제 풀이 아이디어

복잡하게 보이지만 결국 문자열을 다루는 단순한 문제 중에 하나입니다. 문제에 나온대로 그래도 구현해주면 됩니다. 참고로 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 }
}
profile
백과사전 보다 항해일지(혹은 표류일지)를 지향합니다.

0개의 댓글