iOS의 Higher Order Function은 함수를 인자로 받거나 함수를 반환하는 함수를 말한다. 이것은 함수형 프로그래밍의 개념 중 하나로, 함수를 데이터처럼 다룰 수 있게한다.
iOS에서 가장 많이 사용되는 Higher Order Function은 아래와 같다.
map(): 컬렉션 내의 모든 요소를 변경하여 새로운 컬렉션을 생성한다. filter(): 주어진 조건에 맞는 요소만으로 새로운 컬렉션을 생성한다. reduce(): 컬렉션의 모든 요소를 하나의 값으로 줄여준다. sort(): 컬렉션의 요소를 정렬한다. flatMap(): 다차원 컬렉션을 단일 컬렉션으로 평탄화하여 반환한다.
map 함수는 배열의 각 요소를 변환하여 새로운 배열을 만들어 반환하는 함수다. 이를 통해, 기존 배열의 요소를 변환하거나, 새로운 데이터 타입의 배열을 만들 수 있다.
let numbers = [1, 2, 3, 4, 5]
let doubledNumbers = numbers.map({ $0 * 2 })
print(doubledNumbers) // [2, 4, 6, 8, 10]
let numbers = [1, 2, 3, 4, 5]
let stringNumbers = numbers.map({ String($0) })
print(stringNumbers) // ["1", "2", "3", "4", "5"]
let words = ["apple", "banana", "orange"]
let capitalizedWords = words.map({ $0.uppercased() })
print(capitalizedWords) // ["APPLE", "BANANA", "ORANGE"]
배열의 요소 중 조건에 맞는 요소만 추출하여 새로운 배열을 만드는 함수다.
let numbers = [1, 2, 3, 4, 5]
let evenNumbers = numbers.filter({ $0 % 2 == 0 })
print(evenNumbers) // [2, 4]
let words = ["apple", "banana", "orange", "grape", "pear"]
let longWords = words.filter({ $0.count >= 5 })
print(longWords) // ["apple", "banana", "orange"]
let numbers = [1, 2, 3, 4, 5, 6]
let filteredNumbers = numbers.filter({ $0 != 3 })
print(filteredNumbers) // [1, 2, 4, 5, 6]
let numbers: [Int?] = [1, nil, 3, nil, 5]
let filteredNumbers = numbers.filter({ $0 != nil })
print(filteredNumbers) // [1, 3, 5]
아래 처럼 할 수 있지만 굉장히 비효율적이라 이럴땐 Set를 이용하여 더 간단히 해결가능하다.
let numbers = [1, 2, 3, 2, 4, 1, 5]
let uniqueNumbers = numbers.filter({ (index: Int) -> Bool in
let isFirstIndex = numbers.firstIndex(of: index) == numbers.lastIndex(of: index)
return isFirstIndex
})
print(uniqueNumbers) // [3, 4, 5]
Set이용하기
let numbers = [1, 2, 3, 2, 4, 1, 5]
let uniqueNumbers = Array(Set(numbers))
print(uniqueNumbers) // [5, 4, 3, 2, 1]
reduce 메서드는 배열의 모든 요소를 어떠한 방식으로든 하나의 값으로 줄여주는 함수다.
Copy code
let numbers = [1, 2, 3, 4, 5]
let product = numbers.reduce(1, { x, y in
x * y
})
print(product) // 120
let numbers = [3, 9, 2, 8, 6, 5]
let maxNumber = numbers.reduce(numbers[0], { x, y in
x > y ? x : y
})
print(maxNumber) // 9
let strings = ["Hello", ", ", "world", "!"]
let combinedString = strings.reduce("", { x, y in
x + y
})
print(combinedString) // "Hello, world!"
배열을 정렬하는 함수. 기본적으로 오름차순으로 정렬한다.
var numbers = [5, 3, 4, 1, 2]
numbers.sort()
print(numbers) // [1, 2, 3, 4, 5]
var words = ["apple", "banana", "orange", "grape", "pear"]
words.sort(by: { $0.count < $1.count })
print(words) // ["pear", "apple", "grape", "banana", "orange"]
이렇게 sort를 사용하여, 배열을 비교할 수 있는 조건에 따라 정렬할 수 있다. sort 메서드의 인자로는 비교 함수를 사용할 수 있다.
struct Person {
var name: String
var age: Int
}
var people = [
Person(name: "Tom", age: 30),
Person(name: "Jerry", age: 20),
Person(name: "Lucy", age: 25),
Person(name: "Mike", age: 35)
]
people.sort(by: { $0.age < $1.age })
print(people) // [Person(name: "Jerry", age: 20), Person(name: "Lucy", age: 25), Person(name: "Tom", age: 30), Person(name: "Mike", age: 35)]
var numbers = [5, 3, 4, 1, 2]
numbers.sort(by: >)
print(numbers) // [5, 4, 3, 2, 1]
var words = ["apple", "banana", "orange", "grape", "pear"]
words.sort(by: {
if $0 == "orange" { // $0은 첫 번째 비교 요소, $1은 두 번째 비교 요소
return true // $0이 "orange"인 경우 true 반환
} else if $1 == "orange" {
return false // $1이 "orange"인 경우 false 반환
} else {
return $0 < $1 // 나머지 요소는 사전순으로 비교
}
})
print(words) // ["orange", "apple", "banana", "grape", "pear"]
위 코드에서 sort 메서드는 문자열 배열 words를 인자로 받는다. 클로저에서는 "orange" 요소를 우선 정렬하고, 나머지 요소는 사전순으로 정렬한다. 클로저에서는 $0이 "orange"인 경우 true를 반환하여 $0을 더 앞쪽으로 배치한다. $1이 "orange"인 경우 false를 반환하여 $1을 더 뒤쪽으로 배치한다. 이렇게 sort 함수의 클로저에서 특정 요소를 우선 정렬할 수 있다.
flatMap은 배열의 각 요소를 변환하여 새로운 배열을 만들고, 이를 하나의 배열로 평탄화하는 함수. 즉, 다차원 배열을 단일 배열로 만들어 준다.
let numbers = [[1, 2], [3, 4], [5, 6]]
let flattenedNumbers = numbers.flatMap({ $0 })
print(flattenedNumbers) // [1, 2, 3, 4, 5, 6]
클로저에서는 각 배열을 반복하여 하나의 배열로 합쳐주는데, $0은 배열을 나타낸다. 이렇게 flatMap을 사용하여 2차원 배열을 단일 배열로 만들 수 있다.
let words = ["apple", "banana", "orange"]
let wordLengths = words.flatMap({ $0.trimmingCharacters(in: .whitespaces) })
.map({ $0.count })
print(wordLengths) // [5, 6, 6]
이렇게 flatMap을 사용하여 배열의 요소를 변환하고, 새로운 배열을 만들 수 있다. flatMap은 이러한 방식으로, 배열의 요소를 변환하는 데에도 많이 사용된다.
iOS UIKit DevTutorial에 있는 소스 참고 : CollectionView 생성부분
/*
mutating func appendSections(_ identifiers: [SectionIdentifierType])
*/
var snapshot = Snapshot()
snapshot.appendSections([0])
/*
var reminderTitles = [String]()
for reminder in Reminder.sampleData {
reminderTitles.append(reminder.title)
}
snapshot.appendItems(reminderTitles)
*/
snapshot.appendItems(Reminder.sampleData.map { $0.title })
고차함수로 배열을 전환하는 작업은 빈번하다.
이 변환 중에는 nil이 발생할 수가 있는데,
comapctMap은 map과 달리 nil을 자동으로 필터링한다.
두가지 사례를 보자
// MARK: CompactMap
let mixedValues = ["1", "two", "3", "four"]
let numbers = mixedValues.compactMap { Int($0) }
// 결과: [1, 3]
// MARK: Map
let mixedValues = ["1", "two", "3", "four"]
let numbers = mixedValues.map { Int($0) }
// 결과: [Optional(1), nil, Optional(3), nil]
보통 테스트를 위해 더미데이터를 만드는 경우가 많다.
이 때, 중요한것은 반드시 인자가 $0로 들어가야한다는 것이다.
- 231123 : compactMap 추가