map은 자신을 호출할 때 매개변수로 전달된 함수를 실행하여 그 결괏값을 다시 반환해주는 함수이다.map을 사용하기 위해서는 Swift의 collection, sequence 프로토콜을 따르면 가능하다. 따라서 Array, Dictionary,Set,optional 등에서 사용이 가능map을 사용하여도 기존의 컨테이너의 값은 변경되지 않고 새로운 컨테이너가 생성되어 map은 기존 데이터를 변형하는데 많이 사용된다.map 은 다른 함수의 형태로 입력을 받는다.또 , 다중 스레드 환경일 때 대상 컨테이너의 값이 스레드에서 변경되는 시점에 다른 스레드에서도 동시에 값이 변경되려고 할 때 예측하지 못한 결과가 발생하는 부작용을 방지한다.
let item = ["가방", "책", "블로그", "지갑"]
let first = item.map{ (name) in "서근의 " + name }
print(first)
let second = item.map({(name) in "서근의 " + name})
print(second)
let third = item.map {"서근의 " + $0}
print(third)

이것을 클로저로 바꾸면 아래와 같다.
let item = ["가방", "책", "블로그", "지갑"]
func addName(name: String) -> String {
return "서근의 " + name
}
item.map(addName)
for-in 구문과 map 메서드 사용을 비교해보자면 아래와 같다.
let numbers: [Int] = [0, 1, 2, 3, 4]
var doubledNumbers: [Int] = [Int]()
var string: [String] = [String]()
for number in numbers {
doubledNumbers.append(number * 2)
string.append("\(number)")
}
print(doubledNumbers) //[0, 2, 4, 6, 8]
print(string) //[0, 2, 4, 6, 8]
//map 메서드
doubledNumbers = numbers.map({ (number: Int) -> Int in
return number * 2 //[0, 2, 4, 6, 8]
})
string = numbers.map({ (number: Int) -> String in
return "\(number)" //["0", "1", "2", "3", "4"]
})
map 메서드를 사용하면 for-in 구문을 사용한 것보다 간단하고 편하게 연산을 실행할 수 있다. 또, map 메서드를 사용하면 for-in 구문을 사용하기 위해 빈 배열을 생성할 필요도, append 연산을 실행할 시간도 필요가 없어진다!!
위 코드에서 사용된 map 메서드를 클로저 표현으로 요약할 수 있다.
let numbers: [Int] = [0, 1, 2, 3, 4]
//map 메서드
doubledNumbers = numbers.map({ (number: Int) -> Int in
return number * 2 //[0, 2, 4, 6, 8]
})
string = numbers.map({ (number: Int) -> String in
return "\(number)" //["0", "1", "2", "3", "4"]
})
//유형 추론으로 요약 가능
doubledNumbers = numbers.map({ (number) in
return number * 2 //[0, 2, 4, 6, 8]
})
string = numbers.map({ (number) in
return "\(number)" //["0", "1", "2", "3", "4"]
})
//매개변수 및 반환 타입 생략
doubledNumbers = numbers.map({return $0 * 2})
string = numbers.map({return "\($0)"})
//반환 키워드 생략
doubledNumbers = numbers.map({$0 * 2})
string = numbers.map({"\($0)"})
//후행 클로저로 요약 가능
doubledNumbers = numbers.map { $0 * 2 }
string = numbers.map { "\($0)"}
코드의 재사용 측면에 대해 알아보자면 만약 같은 기능을 여러번 사용해야 한다면 하나의 클로저를 여러 map 메서드에서 사용하는 것이 좋다!
let evenNumbers: [Int] = [0, 2, 4, 6, 8, 10]
let oddNumbers: [Int] = [0, 1, 3, 5, 7, 9]
let multiplyTwo: (Int) -> Int = { $0 * 2 }
let doubledEvenNumbers = evenNumbers.map(multiplyTwo)
//[0, 4, 8, 12, 16, 20]
let doubledOddNumbers = oddNumbers.map(multiplyTwo)
//[0, 2, 6, 10, 14, 18]
filter는 내부 값을 걸러서 추출하는 역할을 한다.map과 동일하게 새로운 컨테이너에 걸러진 값을 담아 반환한다.map은 기존의 요소를 변경한 값을 반환했다면, filter는 기준을 가지고 기준에 맞는 값들을 반환해준다.filter 함수의 매개변수로 전달되는 함수 반환 타입은 Bool 이다.true, 그게 아니라면 false 반환let number = [1, 2, 3, 4, 5]
print(number.filter {$0 > 3}) //4, 5
//필터 조건이 맞다면 map조건을 실행
let filterAndMap = [1, 2, 3, 4, 5].filter{$0 > 3}.map{$0 * 10}
print(filterAndMap) //40, 50
이런 식으로 filter 를 사용하여 필요 없는 요소들을 삭제하고 필요한 요소들만 가지고 연산을 하는 게 가능하다 !!
let numbers: [Int] = [0, 1, 2, 3, 4, 5]
var evenNumber: [Int] = numbers.filter { (number: Int) -> Bool in
return number % 2 == 0
}
print(evenNumber) // [0, 2, 4]
let oddNumbers: [Int] = numbers.filter { $0 % 2 == 1 }
print(oddNumbers) // [1, 3, 5]
첫 번째, 클로저가 각 요소를 전달받아 연산한 후 값을 다음 클로저 실행을 위해 반환하며 컨테이너를 순환하는 형태. initialResult 라는 이름의 매개변수로 전달되는 값을 통해 초깃값을 지정하고, nextPartialResult 매개변수로 클로저를 전달받음.
두 번째 , 컨테이너를 순환하며 클로저가 실행되지만 클로저가 따로 결괏값을 반환하지 않는 형태. 대신 inout 매개변수를 사용하여 초깃값에 직접 연산을 실행함.
let number = [1, 2, 3, 4, 5]
let sum1 = number.reduce(0) { (result:Int, element: Int) -> Int in return result + element }
print(sum1) //15
//추론으로 생략 가능
let sum2 = number.reduce(0) { (result, element) in result + element }
print(sum2) //15
let sum3 = number.reduce(0) {$0 + $1}
print(sum3) //15
let sum4 = number.reduce(1, +)
print(sum4) //16
/*
reduce 초기값이 0이기 때문에 0 + 1 부터 시작하여 마지막 값을 결괏값으로 보여준다.
0 + 1
1 + 2
3 + 3
6 + 4
10 + 5
결괏값 = 15
*/