Swift 고차함수 - ehrldyd15/Swift_Skills GitHub Wiki

고차함수 (Higher-order function)

고차 함수란 매개변수로 함수를 갖는 함수

map(_:)

    let cast = ["Vivien", "Marlon", "Kim", "Karl"]

    let lowercaseNames = cast.map { $0.lowercased() }
    // 'lowercaseNames' == ["vivien", "marlon", "kim", "karl"]

    let letterCounts = cast.map { $0.count }
    // 'letterCounts' == [6, 6, 3, 4]

호출할떄 매개변수로 전달된 함수를 실행하여 그 결과를 반환한다.

스위프트의 Sequence, Collection 프로토콜을 따르는 타입은 모두 사용 가능하다.

컨테이너가 담고 있던 각각의 값을 매개변수를 통해 받은 함수에 적용 후 다시 컨테이너에 담아서 반환한다.

기존의 컨테이너의 값은 변경되지 않고 새로운 컨테이너가 생성되어 반환된다.

filter(_:)

    let cast = ["Vivien", "Marlon", "Kim", "Karl"]
    
    let shortNames = cast.filter { $0.count < 5 }
    
    print(shortNames)
    // Prints "["Kim", "Karl"]"

매개변수로 전달되는 함수의 반환타입은 Bool타입이다.

map(_:)처럼 새로운 컨테이너에 값을 담아 반환하지만 기존 컨텐츠를 변형하지 않고 특정 조건에 맞게 걸러내는 역할을 한다.

reduce(_ :_ :)

    let numbers = [1, 2, 3, 4]
    let numberSum = numbers.reduce(0, { x, y in
        x + y
    })

    // numberSum == 10

컨테이너 내부의 컨텐츠를 하나로 합치는 기능을 실행한다.

배열이라면 배열의 모든 값을 전달인자로 받은 클로저의 연산 결과로 합쳐준다.

스위프트의 리듀스는 두가지 형태인데,

첫번쨰 리듀스는 클로저가 각 요소를 전달받아 연산한 후 값을 다음클로저 실행을 위해 반환하며 컨테이너를 순환

두번째 리듀스는 컨테이너를 순환하며 클로저가 실행되지만, 따로 결과값을 반환하지 않음. 대신 inout 매개변수를 사용하여 초기값에 직점 연산을 실행한다.

compactMap(_:)

    let possibleNumbers = ["1", "2", "three", "///4///", "5"]

    let mapped: [Int?] = possibleNumbers.map { str in Int(str) }
    print(mapped)
    // [1, 2, nil, nil, 5]

    let compactMapped: [Int] = possibleNumbers.compactMap { str in Int(str) }
    print(compactMapped)
    // [1, 2, 5]

매개변수로 전달된 클로저가 옵셔널 값을 생산할떄 사용한다.

시퀀스의 각 요소를 전달받은 클로저에 적용하고 nil이 아닌 값들만 배열 추가한 후 반환한다.

flatMap(_:)

    let numbers = [1, 2, 3, 4]

    let mapped = numbers.map { Array(repeating: $0, count: $0) }
    // [1], [2, 2], [3, 3, 3], [4, 4, 4, 4](/ehrldyd15/Swift_Skills/wiki/1],-[2,-2],-[3,-3,-3],-[4,-4,-4,-4)

    let flatMapped = numbers.flatMap { Array(repeating: $0, count: $0) }
    // [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

시퀀스의 각 요소들에 매개변수로 전달된 클로저를 적용하여 연속적인 값을 가지는 배열을 반환한다.

매개변수 클로저가 각 요소에 대한 시퀀스 혹은 컬렉션을 생산할때, 일차원 컬렉션을 얻고자 사용한다.

flatMap, compactMap 심화

    let array = [1, nil, 3, nil, 5, 6, 7]
    let flatMapTest = array.flatMap{ $0 }
    let compactMapTest = array.compactMap { $0 }

    print("flatMapTest :", flatMapTest)
    print("compactMapTest :", compactMapTest)

    <출력>
    flatMapTest : [1, 3, 5, 6, 7]
    compactMapTest : [1, 3, 5, 6, 7]

둘 다 동일한 결과가 나온다. (단, 1차원 배열에서만..)

기존의 flatMap의 경우에는 배열을 flatten하게 만들어주며 nil을 제거, 옵셔널 바인딩해주는 역할이다.

위의 코드는 아래의 경고를 유발한다.

스크린샷 2022-05-20 오전 10 48 38

즉, Swift 4.1부터는 1차원 배열에서 nil을 제거하고 옵셔널 바인딩을 하고싶을때는 compactMap을 사용하면 된다.

    let array: [Int?](/ehrldyd15/Swift_Skills/wiki/Int?) = [1, 2, 3], [nil, 5], [6, nil], [nil, nil](/ehrldyd15/Swift_Skills/wiki/1,-2,-3],-[nil,-5],-[6,-nil],-[nil,-nil)
    let flatMapTest = array.flatMap { $0 }
    let compactMapTest = array.compactMap { $0 }

    print("flatMapTest :",flatMapTest)
    print("compactMapTest :",compactMapTest)

    <출력>
    // flatMapTest : [Optional(1), Optional(2), Optional(3), nil, Optional(5), Optional(6), nil, nil, nil]
    // compactMapTest : [Optional(1), Optional(2), Optional(3)], [nil, Optional(5)], [Optional(6), nil], [nil, nil](/ehrldyd15/Swift_Skills/wiki/Optional(1),-Optional(2),-Optional(3)],-[nil,-Optional(5)],-[Optional(6),-nil],-[nil,-nil)

위 코드처럼 2차원 배열일 경우에는 둘 다 nil을 제거하지않고, 1차원 배열일때만 nil을 제거한다.

flatMap은 2차원 배열을 1차원배열로 만들어주는 반면 compactMap은 1차원 배열로 만들지 않는다.

즉, 2차원 배열을 1차원으로 만들때는 flatMap을 쓰면 된다.

    let array: [Int?](/ehrldyd15/Swift_Skills/wiki/Int?) = [1, 2, 3], [nil, 5], [6, nil], [nil, nil](/ehrldyd15/Swift_Skills/wiki/1,-2,-3],-[nil,-5],-[6,-nil],-[nil,-nil)
    let flatMapTest = array.flatMap { $0 }.compactMap{ $0 }

    <출력>
    // flatMapTest : [1, 2, 3, 5, 6]

위 코드의 경우 2차원 배열을 flatMap으로 1차원배열로 만들어주고 compactMap으로 체이닝을 하면 원하는 값을 얻을 수 있다.

정리

Swift 4.1부터는 1차원 배열에서 nil을 제거하고 옵셔널 바인딩을 하고싶으실때는 compactMap 사용.

2차원 배열을 1차원 배열로 flatten하게 만들때 flatMap을 사용.

참고자료

https://hyunsikwon.github.io/swift/Swift-Functions-01/

https://jinshine.github.io/2018/12/14/Swift/22.%EA%B3%A0%EC%B0%A8%ED%95%A8%EC%88%98(2)%20-%20map,%20flatMap,%20compactMap/