Swift 고차 함수 쉽게 배우기: map, filter, reduce 실전 예제
고차 함수란 무엇인가?
고차 함수(Higher-order function)란 다른 함수를 전달받거나 결과로 반환하는 함수를 말한다. Swift에서는 함수가 일급 객체이기 때문에, 값처럼 함수도 전달하거나 반환할 수 있다.
대표적인 고차 함수로는 다음 세 가지가 있다:
- map: 배열 안의 값을 변형(transform) 하는 함수
- filter: 조건에 맞는 값만 걸러내는 함수
- reduce: 여러 값을 하나로 합치는 함수
map: 배열을 변형할 때
✅ map이 유용한 상황
예를 들어, 학생들의 이름과 성적이 담긴 배열이 있다고 하자. 여기서 각각의 학생 성적 평균을 계산해서, 이름과 평균만 담긴 새로운 배열로 만들고 싶다면 map이 딱이다.
🧩 예시
struct Student {
let name: String
let korean: Int
let english: Int
let math: Int
}
struct Result {
let name: String
let average: Double
}
let students = [
Student(name: "지민", korean: 80, english: 90, math: 85),
Student(name: "정국", korean: 70, english: 75, math: 65)
]
func calculateAverage(_ student: Student) -> Double {
return Double(student.korean + student.english + student.math) / 3.0
}
let resultList = students.map {
Result(name: $0.name, average: calculateAverage($0))
}
여기서 students.map은 학생 배열의 각 요소(Student)를 꺼내서 Result라는 새로운 구조체로 변환하는 과정이다. map은 배열을 하나씩 순회하며, 바꿔주는 역할을 하는 것이다.
filter: 조건에 맞는 것만 남긴다
✅ 언제 쓰면 좋을까?
학생들 중에서 평균이 70점 이상인 학생들만 골라내고 싶다면? 바로 filter를 사용한다.
let passedList: [Result] = students
.map { Result(name: $0.name, average: calculateAverage($0)) }
.filter { $0.average >= 70 }
filter는 true/false를 기준으로 배열을 걸러낸다. 조건에 맞는 값만 남기고, 나머지는 제거된다. 아주 강력하고 유용한 함수다.
reduce : 여러 값을 하나로 합치기
reduce 함수는 배열(혹은 컨테이너)에 있는 여러 개의 값을 하나의 결과값으로 합치는 역할을 한다. 말 그대로 ‘줄이다’ 또는 ‘통합하다’라는 뜻과 같다.
예를 들어, [2, 8, 15]라는 숫자 배열의 모든 값을 더하거나 빼는 작업을 할 때, reduce를 쓰면 훨씬 깔끔하고 간단하다.
기존 방식: for 문을 이용해 합산하기
let someNumbers: [Int] = [2, 8, 15]
var result: Int = 0
for number in someNumbers {
result += number
}
print(result) // 25
- 여기서 for number in someNumbers는 배열 someNumbers 안에 있는 요소들을 하나씩 꺼내서 number라는 변수에 넣어 반복하는 구문이다.
- result라는 변수에 하나씩 더해가는 방식이다.
reduce 함수 사용하기
reduce는 이 과정을 더 간결하게 표현한다.
let sum: Int = someNumbers.reduce(0, { (first: Int, second: Int) -> Int in
return first + second
})
print(sum) // 25
- 여기서 0은 초기값이다.
즉, 합산을 시작할 때의 기준값으로 생각하면 된다. - (first, second)는 reduce가 제공하는 매개변수 이름이다.
- first는 지금까지 계산된 누적값(accumulator)
- second는 현재 배열에서 꺼낸 요소 값(current element)
즉, first + second를 하면서 배열의 모든 요소를 더해간다.
reduce 활용 예시: 빼기 연산
var subtract: Int = someNumbers.reduce(0, { (first: Int, second: Int) -> Int in
return first - second
})
print(subtract) // -25
- 여기서는 누적값에서 배열의 요소를 하나씩 빼는 연산이다.
- 0 - 2 - 8 - 15 = -25가 되는 것이다.
reduce 더 간단하게 쓰기 — 축약형 클로저
Swift에서는 클로저 문법을 줄일 수 있다.
let sumFromThree = someNumbers.reduce(3) { $0 + $1 }
print(sumFromThree) // 28
- 초기값을 3으로 바꿨다.
- $0는 누적값, $1은 현재 값이다.
- 3 + 2 + 8 + 15 = 28이 된다.
first, second는 꼭 이렇게 써야 할까?
npp~! 이건 매개변수 이름일 뿐, 자유롭게 바꿀 수 있다.
예를 들어 이렇게 써도 완벽히 동작한다.
let sum = someNumbers.reduce(0) { total, current in
total + current
}
- total은 누적값
- current는 현재 값
원하는 이름을 써도 무방하다. Swift가 타입을 추론해주기 때문이다(:
🧠 그 외, 문법 복습
지금까지 배워서 알고있지만, 그럼에도 다시 짚어가면 좋은 문법 요소들을 정리해보았다(:
1. $0 이 뭐지?
$0는 map, filter 같은 클로저 안에서 '첫 번째 매개변수'를 의미한다.
$1, $2는 두 번째, 세 번째 매개변수에 해당된다.
예를 들어:
let numbers = [1, 2, 3]
let doubled = numbers.map { $0 * 2 } // $0은 배열 안의 각 숫자
이건 numbers 배열의 각 요소를 꺼내서 2배로 만든 것. $0은 지금 처리 중인 값 하나를 뜻한다.
2. ->는 무엇을 의미할까?
let transform: (Int) -> String = { number in
return "숫자: \(number)"
}
이렇게 생긴 부분에서 ->는 함수의 반환(return) 타입을 나타낸다.
즉, (Int) -> String은 "Int를 받아서 String을 반환하는 함수"란 뜻이다.
3. func sayHello(to name: String) 여기서 to는 왜 필요할까?
이건 외부 매개변수 이름이다. Swift는 함수 호출을 좀 더 읽기 쉽게 하려고, 외부에서 쓰는 이름(to)과 내부 변수(name)를 나눌 수 있게 했다.
func sayHello(to name: String) {
print("Hello, \(name)")
}
sayHello(to: "지민") // 외부에서 "to"를 써야 한다
그렇다면 to를 없애려면?
_를 쓰면 된다.
func sayHello(_ name: String) {
print("Hello, \(name)")
}
sayHello("지민") // to 생략 가능
정리하자면,
함수 선언 | 호출할 때 모습 |
func sayHello(to name: String) | sayHello(to: "지민") |
func sayHello(_ name: String) | sayHello("지민") |
4. let passedList: [Result] = ... 에서 [Result]는 왜 쓰는 걸까?
이건 이 변수의 타입이 Result 타입의 배열이다라고 명시하는 것이다.
- [Result]는 Result 구조체를 담고 있는 배열
- [Int]는 정수를 담고 있는 배열
- [String]은 문자열 배열
타입을 명시해도 되고, 안 해도 된다. 하지만 명확하게 타입을 알려주고 싶을 때 쓰는 것이다.
5. 백틱(`) 기호는 뭐지?
문서나 블로그에서 [Int] 같은 걸 강조할 때, 코드처럼 보이게 하기 위해 백틱 기호를 씌운다.
`[Int]` ← 코드처럼 보이게 하기 위한 표시. 실제 코드에는 없음.
+정리
map | 배열의 각 요소를 다른 값으로 바꿈 |
filter | 조건에 맞는 값만 남김 |
reduce | 여러 값을 하나로 합치거나 줄이는 함수 |
초기값 (초깃값) | 계산을 시작하는 기준값 |
클로저 매개변수 이름 | 임의로 정할 수 있으며, 누적값과 현재값을 의미 |
축약형 클로저 | $0, $1 같은 단축 표현으로 간단히 쓸 수 있음 |
$0 | 클로저에서 첫 번째 값 |
-> | 함수의 반환 타입 |
_ | 외부 매개변수 생략 |
[Result] | Result 타입 배열을 뜻함 |
'IT' 카테고리의 다른 글
앱 시닝 vs 슬라이싱: iOS 앱 최적화 개념 / 에셋 카탈로그, IBOutlet (0) | 2025.05.25 |
---|---|
Swift 핵심 개념 정리 : 제네릭, 프로토콜, ARC와 강한 순환 참조 (0) | 2025.05.23 |
Swift 오류처리 : 자판기 예제로 배우는 throw, throws, try, do-catch, switch-case, defer (0) | 2025.05.21 |
Swift 익스텐션 활용법: 연산 프로퍼티, 메서드, 서브스크립트 추가하기 (0) | 2025.05.14 |
스위프트 프로토콜 vs 클래스 상속: 유연한 기능 구현을 위한 최적의 선택 (0) | 2025.05.11 |
댓글
이 글 공유하기
다른 글
-
앱 시닝 vs 슬라이싱: iOS 앱 최적화 개념 / 에셋 카탈로그, IBOutlet
앱 시닝 vs 슬라이싱: iOS 앱 최적화 개념 / 에셋 카탈로그, IBOutlet
2025.05.25 -
Swift 핵심 개념 정리 : 제네릭, 프로토콜, ARC와 강한 순환 참조
Swift 핵심 개념 정리 : 제네릭, 프로토콜, ARC와 강한 순환 참조
2025.05.23 -
Swift 오류처리 : 자판기 예제로 배우는 throw, throws, try, do-catch, switch-case, defer
Swift 오류처리 : 자판기 예제로 배우는 throw, throws, try, do-catch, switch-case, defer
2025.05.21 -
Swift 익스텐션 활용법: 연산 프로퍼티, 메서드, 서브스크립트 추가하기
Swift 익스텐션 활용법: 연산 프로퍼티, 메서드, 서브스크립트 추가하기
2025.05.14