일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Swift
- Subject
- RxSwift
- 해시
- 풀이
- 차이
- 스위프트
- 리스트뷰
- async
- 클로저
- 프로그래머스
- concurrency
- 프래그먼트
- 연산자
- 백준
- Self
- 자바
- 생명주기
- 옵셔널
- 서브스크립트
- 안드로이드
- 이스케이핑
- View
- 테스크
- weak
- 구조체
- ios
- 알고리즘
- rx
- observable
- Today
- Total
study record
[Swift] 맵, 필터, 리듀스 본문
맵
맵은 자신을 호출할 때 매개변수로 전달된 함수를 실행하여 그 결과를 다시 반환해주는 함수이다. 배열, 딕셔너리, 세트, 옵셔널 등에서 사용할 수 있다.
맵을 사용하면 컨테이너가 담고 있던 각각의 값을 매개변수를 통해 받은 함수에 적용한 후 다시 컨테이너에 포장하여 반환한다. 기존 컨테이너의 값은 변경되지 않고 새로운 컨테이너가 생성되어 반환된다. 맵은 기존 데이터를 변형하는데 많이 사용한다.
map 메서드의 사용법은 for-in 구문과 별 차이가 없다. 다만 코드의 재사용 측면이나 컴파일러 최적화 측면에서 성능 차이가 있다. 다중 스레드 환경일 때 대상 컨테이너의 값이 스레드에서 변경되는 시점에 다른 스레드에서도 동시에 값이 변경되려고 할 때 예측지 못한 결과가 발생하는 부작용을 방지할 수도 있다.
map 메서드를 사용하면 for-in 메서드를 사용하기 위하여 빈 배열을 처음 생성해 주는 작업도 필요 없다. 배열의 append 연산을 실행하기 위한 시간도 필요 없다.
let numbers: [Int] = [0,1,2,3,4]
var doubledNumbers: [Int] = [Int]()
var strings: [String] = [String]()
// for 구문 사용
for number in numbers {
doubledNumbers.append(number*2)
strings.append("\(number)")
}
// map 메서드 사용
doubledNumbers = numbers.map({ number: Int) -> Int in
return number * 2
})
strings = numbers.map({ (number: Int) -> String in
return "\(number)"
})
// 클로저의 반복 사용 활용
let multiplyTwo: (Int) -> Int = {$0 * 2}
let evenNumbers: [Int] = [0,2,4,6,8]
let doubledEvenNumbers = evenNumbers.map(multiplyTwo)
필터
필터는 말 그대로 컨테이너 내부의 값을 걸러서 추출하는 역할을 하는 고차함수이다. 맵처럼 새로운 컨테이너에 값을 담아 반환해준다. 다만 맵처럼 기존 콘텐츠를 변형하는 것이 아니라, 특정 조건에 맞게 걸러내는 역할을 할 수 있다.
filter 함수의 매개변수로 전달되는 함수의 반환 타입은 Bool이다. 새로운 컨테이너에 포함될 항목이라고 판단하면 true를, 포함하지 않으려면 false를 반환한다.
let numbers: [Int] = [0,1,2,3,4,5]
let evenNumbers: [Int] = numbers.filter {(number: Int) -> Bool in
return number % 2 == 0
}
리듀스
리듀스 기능은 결합이라구 불릴 수 있는 기능이다. 리듀스는 컨테이너 내부의 콘텐츠를 하나로 합하는 기능을 실행하는 고차함수이다. 배열이라면 배열의 모든 값을 전달인자로 받은 클로저의 연산결과로 합해준다.
스위프트의 리듀스는 두 가지 형태로 구현되어 있다. 첫 번째 리듀스는 클로저가 각 요소를 전달받아 연산한 후 값을 다음 클로저 실행을 위해 반환하며 컨테이너를 순환하는 형태이다. 두 번째 리듀스 메서드는 컨테이너를 순환하며 클로저가 실행되지만 클로저가 따로 결괏값을 반환하지 않는 형태이다. 대신 초깃값에 직접 연산을 실행한다.
let numbers: [Int] = [1,2,3]
// 첫 번째 형태인 reduce(_:_:) 메서드 사용
// 초깃값이 0이고 정수 배열의 모든 값을 더한다.
var sum: Int = numbers.reduce(0, { (result: Int, next: Int) -> Int in
return result + next
})
// 두 번째 형태인 reduce(into:_:) 메서드 사용
// 초깃값이 0이고 정수 배열의 모든 값을 더한다.
// 첫 번째 리듀스 형태와 달리 클로저의 값을 반환하지 않고 내부에서 직접 이전 값을 변경한다.
sum = numbers.reduce(into: 0, { (result: inout Int, next: Int) in
result += next
})
맵, 필터, 리듀스의 활용
// 서울 외의 지역에 거주하며 25세 이상인 친구
var result: [Frient] = friends.map{ Friend(name: $0.name, gender: $0.gender,
location: $0.location, age: $0.age+1) }
result = result.filter{ $0.filter{ $0.location != "서울" && $0.age >= 25 }
let string: String = result.reduce("결과값") {
$0 + "\n" + "\($1.name) \($1.gender) \($1.location) \($1.age)세"}
맵으로 나이를 한 살씩 더해 새 Friend 배열을 생성한다. 그리고 필터로 서울에 사는 친구들과 25세 미만인 친구들을 걸러내고, 리듀스로 필터링한 후 변형된 자료를 원하는 모양으로 만들었다.
'Swift > 스위프트 프로그래밍' 카테고리의 다른 글
[Swift] 서브스크립트 (0) | 2021.12.26 |
---|---|
[Swift] 모나드 (0) | 2021.12.06 |
[Swift] 옵셔널 체이닝과 빠른 종료 (0) | 2021.12.02 |
[Swift] 스위프트 프로그래밍 - 접근제어 (0) | 2021.11.30 |
[Swift] 스위프트 프로그래밍 - 클로저 (0) | 2021.11.08 |