이전글에서 가장 많이 사용하는 고차함수들인 map, filter, reduce에 대해서 알아봤다. 이번 글에서는 상대적으로 덜 사용하지만, 그래도 자주 사용하는 고차함수들에 대해 알아보려고 한다.
CompactMap

compactMap은
'컨테이너의 각 요소에 조건을 지정하여 호출할 때, nil이 아닌 배열을 반환'하는 함수이다.
compactMap을 설명하기 앞서 아래 가정을 한번 살펴보자.
우선 nil 값이 있는 학생들의 이름을 모아둔 배열이 있다고 가정할 때
let students: [String?] = ["Greed", "Moana", "Zerom", nil, "Musk", nil]
let iOSStudents = students.map { "iOS_" + $0 }
만일, map을 통해 각자의 이름 앞에
"iOS_"를 붙이면 어떻게 될까?

바로 에러가 발생하게 된다.
그 이유는 students 안에 있는 요소들이 모두 옵셔널타입이기 때문이다.
let students: [String?] = ["Greed", "Moana", "Zerom", nil, "Musk", nil]
let iOSStudents = students.map { student -> String? in
if let name = student {
return "iOS_" + name
} else {
return nil
}
}
만약 여기서 이를 해결하기 위해 옵셔널 바인딩을 사용한다면
복잡한 코드를 만들어줘야 한다.
BUT!
여기서 map이 아닌 compactMap을 쓴다면??
let students: [String?] = ["Greed", "Moana", "Zerom", nil, "Musk", nil]
let iOSStudents = students.compactMap { $0 }.map { "iOS_" + $0 }
print(iOSStudents) // ["iOS_Greed", "iOS_Moana", "iOS_Zerom", "iOS_Musk"]
compactMap에 의해 옵셔널 바인딩을 하면서
nil 값이 제외된 새로운 컬렉션을 만들 수 있다.
여기에 map을 활용해 내가 원하는 형태로 데이터를 가공하면 된다.
그럼 원래 원하던 형태로 결과값을 얻을 수 있다.
다시 compactMap을 정리해자면
nil 값을 제거하고
옵셔널 바인딩을 해서 반환해 주는 함수이다.
flatMap

flatMap은
'컨테이너의 각 요소를 사용하여 지정된 조건을 호출할 때, 순차적인 결과의 배열을 반환'하는 함수이다.
순차적인 결과의 배열을 반환한다??
정의만으로는 이해가 안 되는 사람들이 많을 것이다.
바로 코드를 통해 알아보자.
let numbers = [[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]
let flatMapped = numbers.flatMap { $0 }
print(flatMapped)
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
코드를 보면 2차원 배열이 있다.
이 2차원 배열에 flatMap 함수를 적용하니
1차원 배열로 반환되는 것을 알 수 있다.
아 그래서 flat인 건가? 싶은 사람도 있을 것이다.
추측으로는 그렇다.
평탄화(flatten)를 해주기 때문에 이런 이름으로 지어진 것 같다.
알아둬서 나쁘지 않은 정보가 있다.
궁금하다면 아래 접은 글을 펼쳐서 보길 바란다!
바로 flatMap이 compactMap과 같은 역할을 했다는 것이다.
?????
같은 역할을 했다고??
???
그렇다. 또한 했다는 포인트에서 알 수 있듯
과거형이다.
swift 4.1 버전 전까지는 flatMap 역시
1. nil 값을 제거
2. 옵셔널 바인딩
을 해주는 역할도 하였다.
(+ 본인의 역할인 평탄화 역할도)
지금 사용하면 어떻게 되는데??라고 의문이 들 텐데
아래 사진과 같이 된다.

Swift 4.1 버전 이후부터는 flatMap의 해당 기능이 deprecated 되었다고 알고 있다.
또 compactMap을 사용하라고 주의 메시지가 뜬다.
그리고 애플 또한 compactMap을 사용할 것을 권장한다.
그럼 만약 nil 값을 가지고 있는 2차원 배열이라면 어떻게 해야 할까???
let numbers = [[1], [nil, 3], [4, nil, 6]]
let flatMapped = numbers.flatMap { $0 }.compactMap { $0 }
print(flatMapped)
// [1, 3, 4, 6]
flatMap을 통해 평탄화를 해주고
compactMap을 사용하여
옵셔널 바인딩과 nil 값을 제거해 주면 된다.
그렇다면 3차원 배열에 flatMap을 적용하면???
let numbers = [[[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]]
let flatMapped = numbers.flatMap { $0 }
print(flatMapped)
// [[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]
2차원 배열로 바뀌게 된다.
즉, 3차원 배열에 flatMap을 2번 사용하면
평평한 배열(1차원 배열)이 되게 된다.
ForEach

forEach는
'for in 문과 동일한 순서로 컨테이너의 각 요소에 대해 주어진 클로저를 호출'하는 함수이다.
즉 반복문이라는 소리다!
let nums: [Int] = [1, 2, 3, 4]
nums.forEach {
print($0) // 1 2 3 4
}
for in 문과 같이 반복문으로 사용할 수 있다.
하지만 차이점은 존재한다.
우선, for문은 몇 번 출력할지 제어할 수 있다.
하지만 forEach는 컨테이너의 각 요소를 클로저에 던져 이용하기 때문에
요소만큼 출력된다.
즉, forEach문은 반복 횟수를 제어할 수 없다!!!
let nums: [Int] = [1, 2, 3, 4]
for num in nums {
if num == 3 { break }
print(num) // 1 2
}
nums.forEach {
if $0 == 3 { break }
print($0) // 1 2 3 4
}
또한, forEach문은 반복문이 아닌 클로저를 사용하기 때문에
break, continue 사용이 불가능하고
return을 사용해도 클로저에 대한 호출만 종료될 뿐
마지막 요소까지 계속 호출된다.
'# 개발 > Swift' 카테고리의 다른 글
[iOS] Swift의 고차함수1 (map, filter, reduce) (1) | 2024.06.07 |
---|---|
[iOS] 함수형 프로그래밍이란?? (feat. Swift로 알아보는) (1) | 2024.06.03 |
[iOS] 왜 꼭 Main Thread에서만 UI를 그려야 할까? (0) | 2024.06.02 |
[iOS] NaverMap API - Directions(네비게이션 루트 기능) (0) | 2024.05.31 |
[iOS] NaverMap API - Reverse Geocoding (0) | 2024.05.30 |