don't stop believing

Map 사용하기 본문

Swift/Basic

Map 사용하기

Tongchun 2018. 2. 19. 11:42

Map은 자신을 호출할 때 매개별수로 전달된 함수를 실행하여 그 결과를 다시 반환해주는 함수입니다. Swift에서 Map은 Arry, Dictionary, Set, Optional 등에서 사용할 수 있습니다. 조금 더 정확히 말하자면 Swift의 Sequence, Collection 프로토콜을 따르는 타입과 옵셔널은 모두 맵을 사용할 수 있습니다.


Map을 사용하면 컨테이너가 담고 있던 각각의 값을 매개변수를 통해 받은 함수에 적용한 후 다시 컨테이너에 포장하여 반환합니다. 기존 컨테이너의 값은 변경되지 않고 새로운 컨테이너가 생성되어 반환합니다. 그래서 Map은 기존 데이터를 변형하는 데 많이 사용 합니다.


map 메써드의 사용법은 for-in 구문과 별반 차이가 없습니다. 다만 코드의 재사용 측면이나 컴파일러 최적화 측면에서 본다면 성능 차이가 있습니다. 또, 다중 스레드 환경일때 대상 컨테이너의 값이 스레드에서 변경되는 시점에 다른 스레드에서도 동시에 값이 변경되려고 할 때 예측치 못한 결과가 발생하는 부작용을 방지할 수도 있습니다.


아래는 for-in을 이용해 Arry로 있는 숫자에 2를 곱하는 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
let numbers: [Int] = [1, 2, 3, 4, 5, 6]
var doubledNumber: [Int] = [Int]()
var strings: [String] = [String]()
// for
for number in numbers {
doubledNumber.append(number * 2)
strings.append("\(number)")
}
print(doubledNumber) // [2, 4, 6, 8, 10, 12]
print(strings) // ["1", "2", "3", "4", "5", "6"]
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

위 코드를 map을 이용해 변경해 봅시다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let numbers: [Int] = [1, 2, 3, 4, 5, 6]
var doubledNumber: [Int] = [Int]()
var strings: [String] = [String]()
// map
doubledNumber = numbers.map({ (number: Int) -> Int in
return number * 2
})
strings = numbers.map({ (number: Int) -> String in
return "\(number)"
})
print(doubledNumber) // [2, 4, 6, 8, 10, 12]
print(strings) // ["1", "2", "3", "4", "5", "6"]
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

위 map을 사용한 코드를 closure 표현식을 사용해 더 간략화해볼 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let numbers: [Int] = [1, 2, 3, 4, 5, 6]
var doubledNumber: [Int] = [Int]()
var strings: [String] = [String]()
// closure
doubledNumber = numbers.map({ (number: Int) -> Int in
return number * 2
})
//
doubledNumber = numbers.map({ return $0 * 2 })
//
doubledNumber = numbers.map({ $0 * 2 })
// closure
doubledNumber = numbers.map { $0 * 2}
print(doubledNumber) // [2, 4, 6, 8, 10, 12]
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Closure 표현을 간략화하니 조금씩 코드가 더 간결해졌습니다. 그런데 처음에 언급했던 코드의 재사용 측면에 대해 생각해볼 필요가 있습니다. 같은 기능을 여러 번 사용할 것이라면 하나의 Closure를 여러 메서드에서 사용하는 편이 좋을 것 같습니다.

아래와 같이 재사용 가능한 코드로 재구성할 수 있습니다.

1
2
3
4
5
6
7
8
9
let evenNumbers: [Int] = [0, 2, 4, 6, 8]
let oddNumbers : [Int] = [0, 1, 3, 5, 7]
let multiplyTwo: (Int) -> Int = { $0 * 2 }
let doubledEvenNumbers = evenNumbers.map(multiplyTwo)
print(doubledEvenNumbers) // [0, 4, 8, 12, 16]
let doubledOddNumbers = oddNumbers.map(multiplyTwo)
print(doubledOddNumbers) // [0, 2, 6, 10, 14]
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

map 메써드는 배열에서만 사용할 수 있는 것은 아닙니다. 여러 컨테이너 타입에 모두 적용이 가능합니다.

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
let alphabetDictionary: [String: String] = ["a": "A", "b": "B"]
// closure
var keys: [String] = alphabetDictionary.map { (tuple: (String, String)) -> String in
return tuple.0
}
//
keys = alphabetDictionary.map { $0.0 }
print(keys)
//
let values: [String] = alphabetDictionary.map { $0.1 }
print(values)
// Set
var numberSet: Set = [1, 2, 3, 4, 5]
let resultSet = numberSet.map { $0 * 2 }
print(resultSet)
//
let optionalInt: Int? = 3
let resultInt: Int? = optionalInt.map { $0 * 2 }
print(optionalInt)
// range
let range: CountableClosedRange = (0...3)
let resultRange: [Int] = range.map { $0 * 2 }
print(resultRange)
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

map 메서드를 사용해 여러 자료를 손쉽게 연산할 수 있습니다.


'Swift > Basic' 카테고리의 다른 글

Reduce 사용하기  (0) 2018.02.19
Filter 사용하기  (0) 2018.02.19
탈출 클로저 @escaping  (0) 2018.01.31
defer (후처리)  (0) 2018.01.24
Swift Access Control  (0) 2018.01.19