오늘은 Swift가 제공하는 고차함수 중 map, flatMap, compactMap의 차이점에 대해 알아보도록 하겠습니다.
세개의 함수 모두 공통적으로 "map"을 포함하고 있습니다.
map에서 파생된 variation이 flatMap, compactMap인 것 같습니다.
그럼 먼저 map에 대해 알아보겠습니다.
map(_:)
Returns an array containing the results of mapping the given closure over the sequence’s elements.
// Declaration func map<T>(_ transform: (Self.Element) throws -> T) rethrows -> [T]
"시퀀스의 요소를 순회하며 클로저에 매핑한 결과를 새로운 배열로 반환한다."고 설명합니다.
map을 사용해보겠습니다.
// map 예시 코드
let iceCream = ["Mint Choco", "Rainbow Sherbet", "Mom is Alien", "Cherry jubiler"]
let lowercaseNames = iceCream.map { (taste: String) -> String in
return taste.lowercased()
}
let lowercaseNames = iceCream.map { $0.lowercased() } // 축약형
// 'lowercaseNames' == ["mint choco", "rainbow sherbet", "mom is alien", "cherry jubiler"]
map이 하는 기능을 정리해보자면,
💥 시퀀스의 요소를 주어진 클로저의 인자로 전달해서 반환된 값을 새로운 배열로 만들어 반환합니다.
시퀀스를 동일한 클로저로 변형해서 새로운 배열로 만드는 기능이네요!
flatMap(_:)
Returns an array containing the concatenated results of calling the given transformation with each element of this sequence.
// Decalartion func flatMap<SegmentOfResult>(_ transform: (Self.Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
"시퀀스의 각 요소의 transformation(함수)에 따른 결과를 연결된 결과의 배열로 반환한다"고 설명합니다.
map의 설명에 "연결된 결과"라는 키워드가 더 추가된 내용입니다. 연결된 결과가 무엇을 의미하는지 탐구해보겠습니다🧐
선언부를 보면 transform을 거쳐 반환된 결과의 배열이 아닌, 결과의 요소의 배열로 반환해주고 있습니다.
예를 들어 transform을 하는 클로저가 또 시퀀스 또는 배열이나, 컬렉션을 반환한다면 map의 반환 값은 2차원 배열이 될 것입니다.
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]]
이런 상황에서 flatMap은 배열의 요소만을 꺼내어 1차원의 배열로 만들어 리턴해줍니다.
let flatMapped = numbers.flatMap { Array(repeating: $0, count: $0) }
// [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
정리하자면 flatMap은
💥 map + 반환되는 배열을 flat하게 만들어주는 기능이 추가된 메서드입니다.
compactMap(_:)
Returns an array containing the non-nil results of calling the given transformation with each element of this sequence.
// Decalartion func compactMap<ElementOfResult>(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
"시퀀스의 각 요소의 transformation(함수)에 따른 non-nil 결과의 배열로 반환한다"고 설명합니다.
만약 transform이 옵셔널값을 리턴한다면, 그 중 nil은 모두 제거하고 옵셔널은 언래핑된 값만 추출해서 배열에 담아 리턴합니다.
let possibleNumbers = ["1", "2", "three", "///4///", "5"]
let mapped: [Int?] = possibleNumbers.map { str in Int(str) }
// [1, 2, nil, nil, 5]
let compactMapped: [Int] = possibleNumbers.compactMap { str in Int(str) }
// [1, 2, 5]
compactMap은
💥 map + 반환되는 결과 중 nil이 아닌 결과만 거르는 기능이 추가된 메서드입니다.
map
: 시퀀스의 요소를 주어진 클로저의 인자로 전달해서 반환된 값을 새로운 배열로 만들어 반환
flatMap
:map
+ 반환되는 배열을 flat하게 만들어서 반환
compactMap
:map
+ 반환되는 결과 중 nil이 아닌 결과만 반환