본문 바로가기
Algorithm

Swift 알고리즘 관련 문법

by songmoro 2025. 3. 30.
728x90

조건 split

let str = "abd124kbksbjb62".split { !$0.isNumber }
print(str) // ["124", "62"]

 

dict 필터

let s = [1, 2, 2, 3, 3, 3, 4, 4, 4]
let dict = Dictionary(grouping: Array(s).map(String.init), by: { $0 }).filter { $0.value.count > 1 }
print(dict) // ["3": ["3", "3", "3"], "2": ["2", "2"], "4": ["4", "4", "4"]]

 

여러 조건 split

let str = "nabcvcvacbacac".split { $0 == "a" || $0 == "b" || $0 == "c" }.map { String($0) }
print(str) // ["n", "v", "v"]

 

문자열 range

import Foundation

let str = "12afabsaoabctgi0abcsdg"
let pat = "abc"

if let range = str.range(of: pat) {
    print(String(str.prefix(upTo: range.upperBound))) // 12afabsaoabc
}

if let range = str.range(of: pat, options: .backwards) {
    print(String(str.prefix(upTo: range.upperBound))) // 12afabsaoabctgi0abc
}

 

문자열 → 배열, 배열 교체

let str = "123456789"
let (s, e) = (1, 5)
var my_string = Array(str)
my_string.replaceSubrange(s...e, with: Array(my_string[s...e].reversed()))

print(my_string) // ["1", "6", "5", "4", "3", "2", "7", "8", "9"]

 

범위 패턴 매칭

let month = "05"
let notMonth = "13"

print(("01"..."12") ~= month) // true
print(("01"..."12") ~= notMonth) // false

 

contains 정규식

let number = "212312"
let notNumber = "3y3235"

extension String {
    var isSixDigitNumber: Bool {
        let digits = /[0-9]{6}/
        return self.contains(digits) && self.count == 6 ? true : false
    }
}

print(number.isSixDigitNumber) // true
print(notNumber.isSixDigitNumber) // false

 

dict key, value 반환

let airports = ["LHR": "London Heathrow", "YYZ": "Toronto Pearson"]

let airportCodes = [String](airports.keys)
let airportNames = [String](airports.values)

print(airports) // ["LHR": "London Heathrow", "YYZ": "Toronto Pearson"]
print(airportCodes) // ["LHR", "YYZ"]
print(airportNames) // ["London Heathrow", "Toronto Pearson"]

 

범위 slicing

let str = ["123", "234", "345", "456"]
let (s, l) = (1, 2)

let slicing = str.map {
    let slice = Int($0.prefix(s + l).suffix(l))!
    print($0, "->", slice, terminator: ", ")
    return slice
}.filter {
    $0 % 2 == 0
}

print() // 123 -> 23, 234 -> 34, 345 -> 45, 456 -> 56,
print(slicing) // [34, 56]

 

시퀀스

var n = 1
let number = sequence(first: 0) { i in i + 1 == n ? nil : i + 1 }.map { $0 }
print(number) // [0]

n = 10
let number2 = sequence(first: 0) { i in i + 1 == n ? nil : i + 1 }.map { $0 }
print(number2) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 

배열 범위 초기화

let (start, end) = (10, 20)
let arr = [Int](start...end)
print(arr) // [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

 

포함 검색

let str = "012512"
let str2 = "0550505050"
let s = Set(String(str)).isSubset(of: ["0", "5"])
let s2 = Set(String(str2)).isSubset(of: ["0", "5"])

print(s) // false
print(s2) // true

 

소수 알고리즘

import Foundation

func isPrime(_ num: Int) -> Bool {
    if num == 1 { return false }
    else {
        var i = 2
        while i <= Int(sqrt(Double(num))) {
            if num % i == 0 { return false }
            
            i += 1
        }
        return true
    }
}

 

삼항 연산자 대체

func solution1(_ price:Int, _ money:Int, _ count:Int) -> Int64 {
    var totalPrice = -(1...count).reduce(into: Int64(money), { $0 -= Int64($1 * price) })
    return totalPrice > 0 ? totalPrice : 0
}

// 삼항 연산자 -> max

func solution2(_ price:Int, _ money:Int, _ count:Int) -> Int{
    return max((count + 1) * count / 2 * price - money , 0)
}

 

파운데이션 임포트 시간 차이

// import Foundation

let input = Int(readLine()!)!
var stocks = [(Int, Int)]()

for i in 1...input {
    let stock = readLine()!.split(separator: " ").map({ Double(String($0))! })
    stocks.append((Int(stock[0] * stock[1] * 10.0), i))
}

for stock in stocks.sorted(by: { ($0.0, $1.1) > ($1.0, $0.1) }) {
    print(stock.1, terminator: " ")
}

 

import Foundation

 

// import Foundation

 

여러 조건 정렬, 튜플 정렬

let arr = [(1, 2), (2, 1), (1, 1), (6, 9)]
let sorted = arr.sorted { ($0.0, $1.1) < ($1.0, $0.1) }
print(sorted) // [(1, 2), (1, 1), (2, 1), (6, 9)]

 

typealias

typealias person = (weight: Int, height: Int)
let N = Int(readLine()!)!
var people = [person]()

for _ in 0..<N {
    let input = readLine()!.split(separator: " ").map{Int(String($0))!}
    people.append((input[0],input[1]))
}

for p in people {
    let condition = people.filter { p.weight < $0.weight && p.height < $0.height}
    print(condition.count+1, terminator: " ")
}

 

스택 방향

// 진행 방향: 왼쪽 -> 오른쪽
let stack = ["1", "2", "3"]

// 진행 방향: 오른쪽 -> 왼쪽
let reversed = stack.reversed()

 

입출력 개선

import Foundation

let file = FileIO()
print(file.readInt()) // 5 입력 -> 5

final class FileIO {
    private let buffer:[UInt8]
    private var index: Int = 0

    init(fileHandle: FileHandle = FileHandle.standardInput) {
        buffer = Array(try! fileHandle.readToEnd()!) + [UInt8(0)]
    }

    @inline(__always) private func read() -> UInt8 {
        defer { index += 1 }
        return buffer[index]
    }

    @inline(__always) func readInt() -> Int {
        var sum = 0
        var now = read()
        var isPositive = true

        while now == 10 || now == 32 { now = read() }
        if now == 45 { isPositive.toggle(); now = read() }
        while now >= 48, now <= 57 {
            sum = sum * 10 + Int(now - 48)
            now = read()
        }

        return sum * (isPositive ? 1:-1)
    }

    @inline(__always) func readString() -> String {
        var now = read()

        while now == 10 || now == 32 { now = read() }
        let beginIndex = index - 1
        while now != 10, now != 32, now != 0 { now = read() }
        
        return String(bytes: Array(buffer[beginIndex..<(index-1)]), encoding: .ascii)!
    }

    @inline(__always) func readByteSequenceWithoutSpaceAndLineFeed() -> [UInt8] {
        var now = read()
        
        while now == 10 || now == 32 { now = read() }
        let beginIndex = index - 1
        while now != 10, now != 32, now != 0 { now = read() }

        return Array(buffer[beginIndex..<(index-1)])
    }
}

 

stride reduce

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let str = stride(from: 10, to: 5, by: -1).reduce("", { $0 + String(arr[$1]) })
print(str) // 109876

 

n진수 -> 10진수, 10진수 -> n진수 변환

print(String(19, radix: 3))
// 19(10) -> 201(3)

print(Int("201", radix: 3)!)
// 201(3) -> 19(10)

 

A to Z 인덱스 dict

var dict = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".enumerated().reduce(into: [:]) {
    $0[$1.element] = $1.offset + 1
}

print(dict)

/*
["W": 23, "U": 21, "B": 2, "X": 24, "A": 1, "N": 14, "P": 16, "H": 8, "G": 7, "J": 10, "Y": 25, "F": 6, "K": 11, "S": 19, "D": 4, "O": 15, "T": 20, "C": 3, "Q": 17, "R": 18, "I": 9, "M": 13, "V": 22, "Z": 26, "E": 5, "L": 12]
*/

 

computed property

var isAlphabetic: Bool {
    return self.ascii.filter{ 97...122 ~= $0 }.count == 2
}

 

원소 반복 초기화

var visited = [Bool](repeating: false, count: dungeons.count)

 

범위 찾기 components

let answer = s.components(separatedBy: ["{","}"])

 

빈 값없는 split

var b = s.split(separator: "{", omittingEmptySubsequences: true)

 

reduce 타입 캐스팅 초기화

// 1
split.reduce(into: Array<Int>())

// 2
.reduce(([], 0)) { (tuple, day) -> ([Int], Int) in ... }

 

문자형 숫자를 이어 붙였을 때 큰 수 정렬

let numbers = ["0", "1", "2", "3", "4", "5", "6", "7"]
print(numbers.sorted(by: { ($0 + $1) >= ($1 + $0) })) // ["7", "6", "5", "4", "3", "2", "1", "0"]

 

우선순위 힙 구현(0-indexed)

struct PriorityQueue<T: Comparable> {
    private var heap: [T] = []
    private let compare: (T, T) -> Bool
    
    init(_ sort: @escaping (T, T) -> Bool) { self.compare = sort }
    
    var isEmpty: Bool { heap.isEmpty }
    var count: Int { heap.count }
    var top: T? { heap.first }
    
    mutating func push(_ value: T) {
        heap.append(value)
        var i = heap.count - 1
        
        while i > 0, compare(heap[i], heap[(i - 1) / 2]) {
            heap.swapAt(i, (i - 1) / 2)
            i = (i - 1) / 2
        }
    }
    
    mutating func pop() -> T? {
        guard !heap.isEmpty else { return nil }
        if heap.count == 1 { return heap.removeFirst() }
        heap.swapAt(0, heap.count - 1)
        
        var i = 0
        let popped = heap.removeLast()
        
        while true {
            let (left, right) = (i * 2 + 1, i * 2 + 2)
            
            var next = i
            if left < heap.count, compare(heap[left], heap[next]) { next = left }
            if right < heap.count, compare(heap[right], heap[next]) { next = right }
            
            if next == i { break }
            heap.swapAt(i, next)
            i = next
        }
        
        return popped
    }
}

 

set 중복 검사

Set(["1", "2", "2", "3"]) == ["0"]

 

dict 초기화

let year = [2000, 2001, 2002, 2003, 2004, 2005]
let dict: [Int: Int] = Dictionary(uniqueKeysWithValues: zip(year, (0..<year.count)))
print(dict) // [2003: 3, 2000: 0, 2001: 1, 2002: 2, 2004: 4, 2005: 5]

let sizes = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
let dict2 = Dictionary(grouping: sizes) { $0 }
print(dict2) // [1: [1], 3: [3, 3, 3], 2: [2, 2], 4: [4, 4, 4, 4]]

 

2차원 배열 순회

photo.map { $0.reduce(0) { $0 + (score[$1] ?? 0) } }

 

O(1) Remove First

// removeFirst는 O(n)이라서 reversed -> removeLast
goal.forEach { card in
      if let card1 = cards1.first, card1 == card {
          cards1.removeFirst()
          cards.append(card1)
      }
      if let card2 = cards2.first, card2 == card {
          cards2.removeFirst()
          cards.append(card2)
      }
}

 

!Contains

let filtered = "abcdefghijklmnopqrstuvwxyz".filter { !skip.contains($0) }.map { $0 }
// "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

 

reduce에 딕셔너리 사용

// 1
var s = tangerine.reduce(into: [:]) { partialResult, size in
    partialResult[size, default: 0] += 1
}

.reduce((0, 0)).0

// 2
let maps = filtered.enumerated().reduce(into: [:]) { dict, v in
    dict[v.element] = filtered[(v.offset+index) % filtered.count]
}

 

문자열 연결(join)

s.map { String(maps[$0]!) }.joined()

 

정규 표현식 문자열 검사

// 정규 표현식
new_id = new_id.replacingOccurrences(of: "[^a-z0-9-_.]", with: "", options: .regularExpression)
new_id = new_id.replacingOccurrences(of: "(\\.)\\1+", with: ".", options: .regularExpression)
new_id = new_id.replacingOccurrences(of: "^\\.", with: "", options: .regularExpression).replacingOccurrences(of: "\\.$", with: "", options: .regularExpression)

 

배열 마지막 n개 원소 출력

// suffix(n): stack이 n개 이하여도 가능
if stack.suffix(4).map({ String($0) }).joined() == "1231" {
    stack.removeLast(4)
    return $0 + 1
}

 

2차원 배열 popLast

// popLast를 위해서 배열 rotate
var stacks: [[Int]] = Array(repeating: [], count: board.count)

board.reversed().forEach {
    $0.enumerated().forEach {
        if $0.1 != 0 {
            stacks[$0.0].append($0.1)
        }
    }
}

// [[0, 0, 0, 0, 0], [0, 0, 1, 0, 3], [0, 2, 5, 0, 1], [4, 2, 4, 4, 2], [3, 5, 1, 3, 1]]
// -90 -> [[3, 4], [5, 2, 2], [1, 4, 5, 1], [3, 4], [1, 2, 1, 3]]

 

[[1, 2, 3], [2, 2, 3], [3, 3, 3]] 배열 생성

func solution(_ n:Int, _ left:Int64, _ right:Int64) -> [Int] {
    (left...right).map {
        Int(max(Int64($0) / Int64(n) + 1, Int64($0) % Int64(n) + 1))
    }
}
728x90

'Algorithm' 카테고리의 다른 글

파이썬 알고리즘 문법  (0) 2025.03.30
SwiftUI: [1차] 뉴스 클러스터링  (0) 2024.04.04
SwiftUI: [1차] 캐시  (0) 2024.04.03
SwiftUI: 의상  (0) 2024.04.02
SwiftUI: H-Index  (0) 2024.04.02