이 포스팅은 Swift 시리즈 20 편 중 12 번째 글 입니다.
목차
고차 함수
- 다른 함수를 전달인자로 받거나, 함수 실행의 결과를 함수로 반환하는 함수
- 여기서 중요한 것은, 클로저는 일급 객체(시민)이기 때문에 전달인자, 결과값으로 반환이 가능하다.
map
- 컨테이너(array, dictionary, set) 내부의 기존데이터를 변형하여 새로운 컨테이너를 생성
let numbers: [Int] = [0, 1, 2, 3, 4]
var doubledNumbers: [Int]
var strings: [String]
// 기존의 방식
doubledNumbers = [Int]()
strings = [String]()
for number in numbers{
doubledNumbers.append(number * 2)
strings.append("\(number)")
}
// map 사용
doubledNumbers = [Int]()
strings = [String]()
doubledNumbers = numbers.map({ (number: Int) -> Int in
return number * 2
})
strings = numbers.map({(number: Int) -> String in
return "\(number)"
})
// 매개 변수 생략, 반환 키워드 생략, 후행 클로저 사용
doubledNumbers = numbers.map { $0 * 2 }
strings = numbers.map { "\($0)" }
CompactMap
- Nil을 지우면서 map 작업 가능
let numbersWithNil = [5, 15, nil, 3, 9, 12, nil, nil, 17, nil]
// 이 상황에서 그냥 각각에 대해 연산을 수행하면 에러가 난다.
// 아래와 같이 후처리를 해주어야 한다.
let doubledNums = numbersWithNil.map { $0 != nil ? $0! * 2 : nil }
print(doubledNums)
// 출력 결과를 보면 nil이 섞여 있다. 다시 filter를 통해 걸러주어야 한다.
// [Optional(10), Optional(30), nil, Optional(6), Optional(18), Optional(24), nil, nil, Optional(34), nil]
// 이 두작업을 한번에 할 수 있다.
let notNilDoubled = numbersWithNil.compactMap { $0 != nil ? $0! * 2 : nil }
print(notNilDoubled) // [10, 30, 6, 18, 24, 34]
flatMap
- Flat하게 만들어주는 녀석
// 2차원인 경우에 유용하게 사용이 가능하다!
let marks = [[3, 4, 5], [2, 5, 3], [1, 2, 2], [5, 5, 4], [3, 5, 3]]
// for 문을 사용해서 flat하게 만드는 방법이다.
var allMarks = [Int]()
for marksArray in marks {
allMarks += marksArray
}
// 아래와 같은 두 방법으로 사용이 가능하다.
let allMarks2 = marks.flatMap { (array) -> [Int] in
return array
}
let allMarks3 = marks.flatMap { $0 }
print(allMarks3)
// Prints [3, 4, 5, 2, 5, 3, 1, 2, 2, 5, 5, 4, 3, 5, 3]
Nil 지우기
compactMap
flatMap
등이 증정품으로 있다.- 둘다 nil이 아닌 녀석을 뽑아서 컨테이너를 생성해준다.
- 1차원 배열에서는 두 녀석 동작이 모두 같다.
- 하지만 2차원 배열의 경우 flatmap만 동작하여 결과값을 1차원으로 준다.
- compactmap의 경우 동작하지 않는다.
let marksArray = [[3, nil, 5], [2, 5, 3], [1, nil, nil], [5, 5, nil], [3, 5, 3]]
let notNilMarksFlated = marksArray.flatMap { $0 }
print(notNilMarksFlated)
// [Optional(3), nil, Optional(5), Optional(2), Optional(5), Optional(3), Optional(1), nil, nil, Optional(5), Optional(5), nil, Optional(3), Optional(5), Optional(3)]
let notNilMarksCompact = marksArray.compactMap { $0 }
print(notNilMarksCompact)
// [[Optional(3), nil, Optional(5)], [Optional(2), Optional(5), Optional(3)], [Optional(1), nil, nil], [Optional(5), Optional(5), nil], [Optional(3), Optional(5), Optional(3)]]
filter
- 컨테이너 내부의 값을 걸러서 새로운 컨테이너로 추출
// 기존의 방법
var filtered: [Int] = [Int]()
for number in numbers{
if number % 2 == 0 {
filtered.append(number)
}
} // [0, 2, 4]
// filter 사용
let evenNumbers: [Int] = numbers.filter { (number: Int) -> Bool in
return number % 2 == 0
} // [0, 2, 4]
// 매개변수, 반환 타입, 반환 키워드 생략, 후행 클로저
let oddNumbers: [Int] = numbers.filter { $0 % 2 != 0 } [1, 3]
reduce
- 컨테이너 내부의 콘텐츠를 하나로 통합
// 기존의 방법
let someNumbers: [Int] = [2, 8, 15]
var result: Int = 0
for number in someNumbers {
result += number
} // 25
// reduce 사용
let sum: Int = someNumbers.reduce(0, {(first: Int, second: Int) -> Int in
return first + second
})
// 초기값으로부터 모든 값을 빼는 방법
let subtract: Int = someNumbers.reduce(0, { $0 - $1 }) // -25
// 매개변수, 반환 타입, 반환 키워드 생략, 후행 클로저
let sumFromThree = someNumbers.reduce(3) { $0 + $1 }