티스토리 뷰

iOS

[Swift] compactMap, flatMap

Peppo 2022. 9. 1. 00:12
728x90

오늘은 고차함수 compactMap과 flatMap에 대해 공부해 보려고 합니다.

 

먼저 예시로 바로 들어볼게요.

아래와 같은 배열이 있습니다.

let arr = [nil, 1, 2, nil, nil, 5]

 

여기서 nil을 없애고 배열을 반환하고 싶으면 ?

이때 compactMap, flatMap 을 사용하면 돼요!

let arr = [nil, 1, 2, nil, nil, 5]
let compactMap1 = arr.compactMap { $0 }
let flatMap1 = arr.flatMap { $0 }

print("compact:\(compactMap1)")
// compact:[1, 2, 5]
print("flatMap:\(flatMap1)")
// flatMap:[1, 2, 5]

이렇게 맛보기만 해두고

그럼 어떨때 compactMap을 사용하고 flatMap을 사용하는지 파 봅시다.

 


 

compactMap 

 

각 요소를 호출할때, nil 이 아닌 배열을 반환합니다.

 

func compactMap<ElementOfResult>(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

 

역할

1차원 배열 에서 nil을 제거하고 옵셔널 바인딩

 

 

아래는 mapcompactMap을 비교한 예시 입니다.

let numbers = ["42", "19", "notANumber"]
let testMap = numbers.map { Int($0) }
let testCompactMap = numbers.compactMap { Int($0) }
print(testMap)
// [Optional(42), Optional(19), nil]
print(testCompactMap)
// [42, 19]

 

map 에서는 nil과 Optional 상태로 반환이 되서 나오지만,

compactMap에서는 nil 제거, 옵셔널 바인딩 처리가 되서 반환이 되는걸 볼 수 있어요.

 

 

flatMap도 한번 써볼까요?

let testFlatMap = numbers.flatMap { Int($0) }
print(testFlatMap)
// [42, 19]

결과는 compactMap과 같이 나오지만 경고가 뜨는걸 볼수 있어요.

대충 compactMap을 쓰라는 말

 

쓰지말라니 그럼 앞으로 compactMap만 쓰면 되겠네

 

 

아쉽지만 아니에요. flatMap은 이럴때 쓰여요.


 

FlatMap

 

Swift4.1 이상 부터는 compactMap을 사용하라고 하지만, flatMap이 없어지는건 아닙니다.

 

각 요소를 호출할때, 연결된 결과를 포함하는 배열을 반환 합니다. 

 

func flatMap<SegmentOfResult>(_ transform: (Self.Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence

 

역할

n차원 배열 → n-1 차원 배열 변환, compactMap과 같이 nil 제거, 옵셔널 바인딩 처리를 해줍니다.

 

 

이번에도 예시로 같이 볼게요.

let numbers = [[1, 2, 3], [4, 5], [6, 7]]
let mapResult = numbers.map { $0 }
let flatmapResult = numbers.flatMap { $0 }
print("map:\(mapResult)")
// map:[[1, 2, 3], [4, 5], [6, 7]]

print("flatMap:\(flatmapResult)")
// flatMap:[1, 2, 3, 4, 5, 6, 7]

 

2차원 배열의 상수 numbers에 map과 flatMap의 차이가 보이시나요?

 

flatMap의 경우2차원 배열을 1차원 배열로 만든후 반환을 했습니다.

 

그럼 실험을 하나 더 해볼게요.

numbers 배열을 조금 바꿔보겠습니다.

let numbers = [[1, nil, 3], [4, 5], [6, 7]]

 

nil이 추가가 됐네요. 

 

이 상태에서 flatMap을 돌려본다면?

let flatmapResult = numbers.flatMap { $0 }
print("flatMap:\(flatmapResult)")
// flatMap:[Optional(1), nil, Optional(3), Optional(4), Optional(5), Optional(6), Optional(7)]

와우 Optional .. 

그치만 여기서도 1차원 배열로 만들어 주는걸 확인할 수 있죠.

 

한번더 flatMap을 써볼게요.

let numbers = [[1, nil, 3], [4, 5], [6, 7]]
let mapResult = numbers.map { $0 }
let flatmapResult = numbers.flatMap { $0 }
print("flatMap:\(flatmapResult)")
// flatMap:[Optional(1), nil, Optional(3), Optional(4), Optional(5), Optional(6), Optional(7)]

let flatmapResult2 = flatmapResult.flatMap { $0 }
print(flatmapResult2)
// [1, 3, 4, 5, 6, 7]

 

flatMap의 역할대로 n - 1 차원 배열 -> nil 제거, 옵셔널 바인딩을 해준걸 확인할 수 있습니다.

 


정리

 

1차원 배열 에서 nil 제거, 옵셔널 바인딩 

👇👇👇

compactMap

 

2차원 배열 → 1차원 배열, nil 제거, 옵셔널 바인딩

👇👇👇

flatMap

728x90