본문 바로가기

DEV

[iOS/Swift] 이중우선순위 큐, components(sparatedBy:), split(separator:)

반응형

오늘은 알고리즘 코드카타 시간에 이중우선순위 큐 문제를 풀었다.

https://school.programmers.co.kr/learn/courses/30/lessons/42628

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

레벨 3 치곤 생각보다 쉬웠다.

지금까지 코드카타에서 푼 문제 중 처음으로 당일 시간 안에 풀었다. 

 

코드

import Foundation

func solution(_ operations:[String]) -> [Int] {
    
    var queue = [Int]()
    var minMax = [0, 0]
    
    for operation in operations {
        var opr = operation.split(separator: " ")[0]
        var val = Int(operation.split(separator: " ")[1])!
        
        
        if opr == "I" {
            queue.append(val)
        } else if val == 1 {
            queue.sort()
            if !queue.isEmpty {
                queue.removeLast()
            }
        } else if val == -1 {
            queue.sort()
            if !queue.isEmpty {
                queue.removeFirst()
            }
        }
    }
    
    minMax[0] = queue.max() ?? 0
    minMax[1] = queue.min() ?? 0
    
    
    return minMax
}

 

 

시간이 남아 다른 사람들의 풀이를 훑어 봤다.

보던 중 아래 코드가 되게 깔끔해서 눈이 갔다.

이 코드에서는 forEach로 operation의 요소들을 각각 받아서 .components(seperatedBy: " ")로 나눠서 removeSpace 변수에 넣어서 이어나갔다.

removeSpace를 print 해보면 아래와 같이 나온다.

components(seperatedBy:)에 대해 처음 접해봐서 더 알아봤다.

components(separatedBy:)

https://developer.apple.com/documentation/foundation/nsstring/1413214-components

 

components(separatedBy:) | Apple Developer Documentation

Returns an array containing substrings from the receiver that have been divided by a given separator.

developer.apple.com

components(separtedBy:)는 문자열(String)을 특정 구분 기호(separator)를 기준으로 나누어 배열([String])로 반환하는 메서드라고 한다.

보니깐 .split()과 비슷한 것 같아서 둘의 차이점을 Grok으로 알아봤다.

 

components(separatedBy:)  vs  split(separator:)

1. 기본 출처, 설계

components는 Objective-C의 NSString에서 유래된 메서드이고, split은 Swift 네이티브 메서드라고 한다.

 

2. 반환 타입

components(separatedBy:)는 항상 [String]을 반환한다.

let str = "apple,banana,orange"
let result = str.components(separatedBy: ",")
print(result) // ["apple", "banana", "orange"]

 

반면, split(separator:)는  [Substring](서브스트링 배열)을 반환한다.

Substring은 String과 비슷하지만 메모리 효율성을 위해 원본 문자열을 참조하는 자료형이라고 한다.

split에서 String으로 변환하려면 map { String($0) } 과 같은 추가 작업이 필요하다.

let str = "apple,banana,orange"
let result = str.split(separator: ",")
print(result) // ["apple", "banana", "orange"] (Substring 타입)
let stringArray = result.map { String($0) } // ["apple", "banana", "orange"] (String 타입)

 

3. 구분 기호 처리 방식

components(separatedBy:)는 구분 기호로 문자열이나 CharacterSet을 사용할 수 있다. (CharacterSet은 특정 문자 집합을 나타내는 것이라고 한다. 나중에 더 자세히 알아봐야겠다.)

그리고, 연속된 구분 기호가 있을 경우 빈 문자열("")을 포함한 배열을 반환한다.

let str = "one,,three"
let result = str.components(separatedBy: ",")
print(result) // ["one", "", "three"]

 

CharacterSet을 이용하여 아래처럼 모음 문자를 없앨 수도 있다.

let customSet = CharacterSet(charactersIn: "aeiou") // 모음만 포함
let str = "Swift is fun"
let vowelsRemoved = str.components(separatedBy: customSet).joined()
print(vowelsRemoved) // "Swft s fn"

 

 

split(separator:)은 단일 문자(Character)만 구분 기호로 사용 가능하다.

기본적으로 연속된 구분 기호 사이의 빈 요소를 생략하지만, omittingEmptySubsequences 매개변수를 false로 설정하면 빈 요소를 포함한다.

let str = "one,,three"
let result1 = str.split(separator: ",") // 기본값: 빈 요소 생략
print(result1) // ["one", "three"]
let result2 = str.split(separator: ",", omittingEmptySubsequences: false)
print(result2) // ["one", "", "three"]

 

4. 성능 및 메모리

성능 측면에서는 components(separatedBy:)가 즉시 String 배열을 생성한다.

하지만, split(separator:)는 원본 String을 참조하는 Substring을 반환하기에 메모리 효율 측면에서 더 좋다고 한다.

 

앞으로 components(separatedBy:)를 유용하게 자주 써먹어봐야겠다.

 


추가로 기존 내 코드에서 else if 문 다음마다 queue.sort()를 했는데, 그럴 필요가 없었다..

removeLast(), removeFirst()로 최소, 최대값을 제거하기 위해 sort를 했었는데, 어짜피 sort를 새로하는 것은 append를 한 이후에 하면 되기에 중복해서 넣을 필요가 없었다.

그래서 아래처럼 append를 한 후에만 sort()를 해주었다.

import Foundation

func solution(_ operations:[String]) -> [Int] {
    
    var queue = [Int]()
    var minMax = [0, 0]
    
    for operation in operations {
        var opr = operation.split(separator: " ")[0]
        var val = Int(operation.split(separator: " ")[1])!
        
        
        if opr == "I" {
            queue.append(val)
            queue.sort()
        } else if val == 1 {
            if !queue.isEmpty {
                queue.removeLast()
            }
        } else if val == -1 {
            if !queue.isEmpty {
                queue.removeFirst()
            }
        }

    }
    
    minMax[0] = queue.max() ?? 0
    minMax[1] = queue.min() ?? 0
    
    
    return minMax
}

 

반응형