알고리즘/Programmers

[Swift_Programmes] 문자열 내 마음대로 정렬하기

YEN_ 2024. 1. 3. 12:22

 

프로그래머스 문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/12915

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr


💡 내가 제출한 풀이

func solution(_ strings:[String], _ n:Int) -> [String] {
    
   let sortedStrings = strings.sorted {
        let index0 = $0.index($0.startIndex, offsetBy: n)
        let index1 = $1.index($1.startIndex, offsetBy: n)
        
        if $0[index0] == $1[index1] {
            return $0 < $1
        } else {
            return $0[index0] < $1[index1]
        }
    }
    
    return sortedStrings
}

💡 풀이 과정

 

 

✔️ 문제 해결을 위한 접근 방식

처음에는 문제의 요점을 파악하는게 중요하다.

내가 생각했을 때 이 문제의 요점은 문자열의 인덱스 n번째 글자를 기준으로 오름차순 정렬 이 문장이었다.

 

우선 오름차순 정렬은 어떤 메소드로 할 수 있는지 생각했다.

sorted(by: >) 메소드를 사용하면 오름차순 정렬을 할 수 있다는 것을 생각해냈다.

이전에 sorted를 사용해서 풀었던 문제들
https://yy-dev.tistory.com/72 https://yy-dev.tistory.com/54 https://yy-dev.tistory.com/45

 

 

이제 기준만 담아서 오름차순을 할 수 있게 설정해주면 된다.

https://developer.apple.com/documentation/swift/array/sorted(by:)

 

sorted(by:) | Apple Developer Documentation

Returns the elements of the sequence, sorted using the given predicate as the comparison between elements.

developer.apple.com

 

공식 문서를 보면 알 수 있듯이 by 부분에 클로저를 담아서 사용할 수 있다.

enum HTTPResponse {
    case ok
    case error(Int)
}


let responses: [HTTPResponse] = [.error(500), .ok, .ok, .error(404), .error(403)]
let sortedResponses = responses.sorted {
    switch ($0, $1) {
    // Order errors by code
    case let (.error(aCode), .error(bCode)):
        return aCode < bCode


    // All successes are equivalent, so none is before any other
    case (.ok, .ok): return false


    // Order errors before successes
    case (.error, .ok): return true
    case (.ok, .error): return false
    }
}
print(sortedResponses)
// Prints "[.error(403), .error(404), .error(500), .ok, .ok]"

 

 

 

✔️ 마주친 에러 : 문자열 인덱스 접근

/Solution/Sources/Solution/Solution.swift:6:36: error: 'subscript(_:)' is unavailable: cannot subscript String with an Int, use a String.Index instead.
    let test = strings.sorted(by: {$0[n] > $1[n]})
                                   ^~~~~
Swift.String:3:12: note: 'subscript(_:)' has been explicitly marked unavailable here
    public subscript(i: Int) -> Character { get }
           ^
/Solution/Sources/Solution/Solution.swift:6:44: error: 'subscript(_:)' is unavailable: cannot subscript String with an Int, use a String.Index instead.
    let test = strings.sorted(by: {$0[n] > $1[n]})
                                           ^~~~~
Swift.String:3:12: note: 'subscript(_:)' has been explicitly marked unavailable here
    public subscript(i: Int) -> Character { get }

 

해당 에러는 'subscript(_:)' 함수가 String에 대해 Int로 서브스크립팅을 할 수 없다고 보여주고 있다.

 

Swift는 String의 인덱싱을 할 때 Int를 사용하는 것을 허용하지 않고 있다.

문자열은 유니코드 문자의 모음으로 구성되어 있기 때문이다. 

 

따라서 특정 인덱스의 문자에 접근하려면 String.Index를 사용해주어야 한다.

https://developer.apple.com/documentation/swift/string/index

 

String.Index | Apple Developer Documentation

A position of a character or code unit in a string.

developer.apple.com

 

index(_:offsetBy:) 메소드는 오프셋을 기반으로 새로운 인덱스를 계산해준다.

 

// 틀린 접근
$0[n]
$1[n]

// 옳은 접근
$0.index($0.startIndex, offsetBy: n)
$1.index($1.startIndex, offsetBy: n)

 

이렇게 사용하면 안정적으로 String의 특정 인덱스에 접근할 수 있다

 

 

✔️ 마주친 에러 : 인덱스의 문자가 같을 경우

처음에 조건을 대충읽어서.. 이 부분을 간과했다.

만약 문자열의 n번째 인덱스가 같은 문자라면? 단순히 문자를 비교해서 오름차순 정렬을 할 수 없게 된다.

 

따라서 비교하는 문자가 같을 경우의 조건문을 만들어서 다른 로직을 걸어주는 게 올바르다.

나는 문자가 같을 경우, 전체 문자열을 오름차순으로 비교했다.

문자가 다를 경우는 평범하게 인덱스에 해당하는 문자를 기준으로 오름차순으로 비교했다.

 

let index0 = $0.index($0.startIndex, offsetBy: n)
let index1 = $1.index($1.startIndex, offsetBy: n)
        
if $0[index0] == $1[index1] {
        return $0 < $1
    } else {
         return $0[index0] < $1[index1]
	}
}