[Swift] Higher-order Function


Higher-order Function


고차 함수

  • 함수를 파라미터로 사용하거나 함수 실행의 결과를 함수로 리턴하는 함수
  • 스위프트 뿐만 아니라 함수형 언어를 지향하는 다른 언어들에서도 정의되고 널리 쓰이는 함수들
    • map 함수 / filter 함수 / reduce 함수
    • Collection에 기본적으로 구현되어 있는 함수
      (정확하게는 Sequence, Collection 프로토콜을 따르는 타입)
    • Optional 타입에도 구현되어 있음

map 함수

  • 기존 배열 등의 각 아이템을 클로저로 제공한 방식대로 새롭게 매핑해서 새로운 배열을 리턴하는 함수
  • 각 아이템을 매핑해서, 변형해서 새로운 배열을 만들 때 사용
let numbers = [1, 2, 3, 4, 5]

//(Collection).map(transform: (타입) throws -> T)

var newNumbers1 = numbers.map { (num) in
    return "숫자: \(num)"
}

var newNumbers2 = numbers.map { "숫자: \($0)" }

print(newNumbers1)
print(newNumbers2)
// ["숫자: 1", "숫자: 2", "숫자: 3", "숫자: 4", "숫자: 5"]

filer 함수

  • 기존 배열 등의 각 아이템을 조건(조건은 클로저가 제공)을 확인후, 참(true)을 만족하는 아이템을 걸러내서 새로운 배열을 리턴하는 함수
  • 각 아이템을 필터링해서, 걸러내서 새로운 배열을 만들때 사용
let names = ["Apple", "Black", "Circle", "Dream", "Blue"]

//(Collection).filter(isIncluded: (타입) throws -> Bool)

var newNames = names.filter { (name) -> Bool in
    return name.contains("B")
}

print(newNames)
// ["Black", "Blue"]

let array = [1, 2, 3, 4, 5, 6, 7, 8]

var evenNumersArray1 = array.filter { num in
    return num % 2 == 0
}

var evenNumersArray2 = array.filter { $0 % 2 == 0 }

print(evenNumersArray)
print(evenNumersArray)
// ["2", "4", "6", "8"]

// 클로저이기 때문에 함수로 바꿔서 전달하기도 가능
func isEven(_ i: Int) -> Bool {
    return i % 2 == 0
}
let evens = array.filter(isEven)

// filter의 리턴 값이 배열이기 때문에 두번 적용하기도 가능
evenNumersArray = array.filter { $0 % 2 == 0 }.filter { $0 < 5 }
print(evenNumersArray)

reduce 함수

  • 기존 배열 등의 각 아이템을 클로저가 제공하는 방식으로 결합해서 마지막 결과값을 리턴하는 함수 (초기값 제공할 필요)
  • 각 아이템을 결합해서 단 하나의 값으로 리턴
var numbersArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

//numbersArray.reduce(initialResult: Result, nextPartialResult: (Result, Int) throws -> Result)

var resultSum1 = numbersArray.reduce(0) { (sum, num) in
    return sum + num
}

print(resultSum1)
// 55

var resultSum2 = numbersArray.reduce("0") { $0 + $1 }

print(resultSum2)
// 012345678910

map, filter, reduce의 응용

numbersArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// 위의 배열 중에, 홀수만 제곱해서, 그 숫자를 다 더한 값은?

var newResult = numbersArray
                        .filter { $0 % 2 != 0 }
                        .map { $0 * $0 }
                        .reduce(0) { $0 + $1 }

print(newResult)
// 1, 9, 25, 49, 81 ===> 165

forEach 함수

  • 기존 배열 등의 각 아이템을 활용해서 각 아이템별로 클로저가 제공하는 특정 작업을 실행
  • 각 아이템을 활용해서 각각 특정 작업을 실행할때 사용
let immutableArray = [1, 2, 3, 4, 5]

immutableArray.forEach { num in
    print(num)
}

immutableArray.forEach { print("숫자: \($0)") }

compactMap 함수

  • 기존 배열 등의 각 아이템을 새롭게 클로저가 제공하는 방식으로 매핑해서 변형하되, 옵셔널 요소는 제거하고, 새로운 배열을 리턴
    (map + 옵셔널제거)
  • 옵셔널 바인딩의 기능까지 내장
let stringArray: [String?] = ["A", nil, "B", nil, "C"]

var newStringArray = stringArray.compactMap { $0 }

print(newStringArray)
// ["A", "B", "C"]

let numbers = [-2, -1, 0, 1, 2]

var positiveNumbers = numbers.compactMap { $0 >= 0 ? $0 : nil }

// compactMap은 아래와 같이 filter와 map으로도 구현 가능
var newStringArray = stringArray.filter { $0 != nil }.map { $0! }

print(newStringArray)
print(positiveNumbers)
// [0, 1, 2]

flatMap 함수

  • 중첩된 배열의 각 배열을 클로저가 제공하는 방식으로 새롭게 매핑해서 내부 중첩된 배열을 제거하고 리턴
  • 중첩배열을 flat하게 매핑
var nestedArray = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

print(nestedArray.flatMap { $0 })
// 중첩 배열 제거
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

var newNnestedArray = [[[1,2,3], [4,5,6], [7, 8, 9]], [[10, 11], [12, 13, 14]]]

var numbersArray = newNnestedArray
                            .flatMap { $0 }
                            .flatMap { $0 }

print(numbersArray)
// 이중으로 중첩된 배열 이중으로 제거
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

참고

Ellen Swift Class






© 2021. by hminkim