Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
반응형
Archives
Today
Total
관리 메뉴

슈프림 블로그

[프로그래머스] 2018 카카오 블라인드 코딩테스트 - 파일명 정렬 (Swift 풀이) 본문

코딩테스트

[프로그래머스] 2018 카카오 블라인드 코딩테스트 - 파일명 정렬 (Swift 풀이)

_슈프림 2021. 4. 15. 17:03
728x90

 

programmers.co.kr/learn/courses/30/lessons/17686?language=swift

 

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

파일명 정렬 세 차례의 코딩 테스트와 두 차례의 면접이라는 기나긴 블라인드 공채를 무사히 통과해 카카오에 입사한 무지는 파일 저장소 서버 관리를 맡게 되었다. 저장소 서버에는 프로그램

programmers.co.kr

 

문자열들을 특정 조건에 맞게 정렬하는 문제다.

 

문자열 구성

  • 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 }
반응형
Comments