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