1️⃣ 맵
자신을 호출할 때 매개변수로 전달된 함수를 실행하여 그 결과를 다시 반환해주는 함수
기존 데이터를 변형하는데 많이 사용
map 매서드를 클로저 표현을 이용하여 간략화하기
let numbers: [Int] = [0, 1, 2, 3, 4]
// 기본 클로저의 표현식 사용
var doubleNumbers = numbers.map({(number: Int) -> Int in
return number * 2})
// 매개변수 및 반환 타입 생략
doubleNumbers = numbers.map({return $0 * 2})
print(doubleNumbers)
// 반환 키워드 생략
doubleNumbers = numbers.map({ $0 * 2})
print(doubleNumbers)
// 후행 클로저 사용
doubleNumbers = numbers.map { $0 * 2 }
print(doubleNumbers)
// [0, 2, 4, 6, 8]
클로저의 반복 사용 (재사용)
let evenNumbers: [Int] = [0,2,4,6,8]
let oddNumbers: [Int] = [1,3,5,7,9]
let multiplyTwo: (Int) -> Int = { $0 * 2 }
let doubleEvenNumbers = evenNumbers.map(multiplyTwo)
print(doubleEvenNumbers)
let doubleOddNumbers = oddNumbers.map(multiplyTwo)
print(doubleOddNumbers)
// [0, 4, 8, 12, 16]
// [2, 6, 10, 14, 18]
다양한 컨테이너 타입에서 맵의 활용
let alphabetDictionary: [String: String] = ["a": "A", "b": "B"]
// keys 설정 (1)
var keys: [String] = alphabetDictionary.map{ (tuple: (String, String)) ->
String in
return tuple.0
}
// keys 설정 (2)
keys = alphabetDictionary.map{ $0.0 }
let values: [String] = alphabetDictionary.map{ $0.1 }
print(keys) // ["a", "b"]
print(values) // ["A", "B"]
var numberSet: Set<Int> = [1, 2, 3, 4, 5]
let resultSet = numberSet.map{ $0*2 }
print(resultSet) // [2, 4, 6, 10, 8]
var optionalInt: Int? = 3
let resultInt: Int? = optionalInt.map{ $0*2 }
print(resultInt!) // 6
let range: CountableClosedRange = (0...3)
let resultRange: [Int] = range.map{ $0*2 }
print(resultRange) // [0, 2, 4, 6]
2️⃣ 필터
컨테이너 내부의 값을 걸러서 추출하는 역할을 하는 고차함수
필터 메서드의 사용
let numbers: [Int] = [0, 1, 2, 3, 4, 5]
let evenNumbers: [Int] = numbers.filter{ (number: Int) -> Bool in
return number % 2 == 0
}
print(evenNumbers)
let oddNumbers: [Int] = numbers.filter{ (number: Int) -> Bool in
return number % 2 == 1
}
print(oddNumbers)
// [0, 2, 4]
// [1, 3, 5]
맵과 필터 메서드의 연계 사용
let numbers: [Int] = [0, 1, 2, 3, 4, 5]
let mappedNumbers: [Int] = numbers.map{($0 + 3)}
let evenNumbers: [Int] = mappedNumbers.filter{ (number: Int) -> Bool in
return number % 2 == 0
}
print(evenNumbers)
let oddNumbers: [Int] = mappedNumbers.filter{ (number: Int) -> Bool in
return number % 2 == 1
}
print(oddNumbers)
// [4, 6, 8]
// [3, 5, 7]
3️⃣ 리듀스
컨테이너 내부의 콘텐츠를 하나로 합하는 기능을 실행하는 고차함수
1. 리듀스의 첫번째 형태 reduce(_:_:)
let numbers: [Int] = [1,2,3]
// 첫번째 형태인 reduce(_:_:) 메서드의 사용
// (1) 초깃값이 0이고 정수 배열의 모든 값을 더한다.
var sum: Int = numbers.reduce(0, {(result: Int, next: Int) -> Int in
print("\(result) + \(next)")
return result + next
})
print(sum)
// 0 + 1
// 1 + 2
// 3 + 3
// 6
// (2) 초깃값이 0이고 정수 배열의 모든 값을 뺀다.
var subtract: Int = numbers.reduce(0, {(result: Int, next: Int) -> Int in
print("\(result) - \(next)")
return result - next
})
print(subtract)
// 0-1
// -1-2
// -3-3
// -6
// (3) 초깃값이 3이고 정수 배열의 모든 값을 더한다
var sumFromThree: Int = numbers.reduce(3) {
print("\($0) + \($1)")
return $0 + $1
}
print(sumFromThree)
// 3+1
// 4+2
// 6+3
// 9
// (4) 초깃값이 3이고 정수 배열의 모든 값을 뺀다
var subtractFromThree: Int = numbers.reduce(3){
print("\($0) - \($1)")
return $0 - $1
}
print(subtractFromThree)
// 3-1
// 2-2
// 0-3
// -3
// (5) 문자열 배열을 reduce(_:_:) 메서드를 이용해 연결시킨다.
let names: [String] = ["Chope", "Jay", "Joker", "Nova"]
let reduceNames: String = names.reduce("yejin's friend: ") {
return $0 + ", " + $1
}
print(reduceNames)
//yejin's friend: , Chope, Jay, Joker, Nova
2. 리듀스의 두번째 형태 reduce(into:_:)
// 두번째 형태인 reduce(into:_:) 메서드의 사용
// (1) 초깃값이 0이고 정수 배열의 모든 값을 더한다.
// - 첫번째 리듀스 형태와 달리 클로저의 값을 반환하지 않고 내부에서 직접 이전 값을 변경한다는 점이 다름
sum = numbers.reduce(into: 0, {(result: inout Int, next: Int) in
print("\(result) + \(next)")
result += next
})
print(sum)
// 0+1
// 1+2
// 3+3
// 6
// (2) 초깃값이 3이고 정수 배열의 모든 값을 뺀다.
// - 첫번째 리듀스 형태와 달리 클로저의 값을 반환하지 않고 내부에서 직접 이전 값을 변경한다는 점이 다름
subtractFromThree = numbers.reduce(into: 3, {
print("\($0) - \($1)")
$0 - $1
})
print(subtractFromThree)
//3 - 1
//3 - 2
//3 - 3
//3
맵, 필터, 리듀스의 연계 사용
let numbers: [Int] = [1, 2, 3, 4, 5, 6, 7]
// 짝수를 걸러내어 각 값에 3을 곱한 후 모든 값을 더한다.
var result: Int = numbers.filter{ $0.isMultiple(of: 2) }.map{ $0 * 3 }.reduce(0){ $0 + $1 }
print(result) // 36
// for-in 구문 사용 시
result = 0
for number in numbers{
guard number.isMultiple(of: 2) else {
continue
}
result += number * 3
}
print(result) // 36
4️⃣ 맵, 필터, 리듀스의 활용
enum Gender {
case male, female, unknown
}
struct Friend {
let name: String
let gender: Gender
let location: String
var age: UInt
}
var friends: [Friend] = [Friend]()
friends.append(Friend(name: "yejin", gender: .female, location: "서울", age: 22))
friends.append(Friend(name: "jaeyong", gender: .male, location: "미래관", age: 24))
friends.append(Friend(name: "jonghwan", gender: .male, location: "경기", age: 28))
friends.append(Friend(name: "inhye", gender: .female, location: "대전", age: 22))
// 서울 외의 지역에 거주중인 25살 이상의 친구 찾기
// 작년 자료이므로 한살 더 먹게 하기!
var result: [Friend] = friends.map{ Friend(name: $0.name, gender: $0.gender, location: $0.location, age: $0.age+1)}
result = result.filter{ $0.location != "서울" && $0.age >= 25 }
let resultString: String = result.reduce(" 서울 외의 지역에 거주하며 25세 이상인 친구 "){
"\($0)\n\($1.name) \($1.age) \($1.location) \($1.gender)"
}
print(resultString)
// 서울 외의 지역에 거주하며 25세 이상인 친구
//jonghwan 29 경기 male
1. 맵으로 나이를 한살씩 더해 새로운 Friend 배열을 생성
2. 필터로 서울에 사는 친구들과 25세 미만인 친구들을 걸러낸 후
3. 리듀스로 필터링한 후 변형된 자료를 원하는 모양으로 합쳐서 출력
Reference
Swift 스위프트 프로그래밍 - 야곰
'Swift' 카테고리의 다른 글
[Swift] zip(_:_:) (0) | 2022.07.27 |
---|---|
[Swift] 모나드 : 컨텍스트, 함수객체, 모나드 (0) | 2022.03.24 |
[Swift] 옵셔널 체이닝과 빠른 종료 (guard, assert) (0) | 2022.03.20 |
[Swift] 클로저 : Closure (0) | 2022.03.20 |
[Swift] 접근제어 : 읽기 전용 구현 (0) | 2022.03.19 |