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를 곱하는 코드입니다.

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"]

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

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"]

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

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]

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

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

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]

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

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)

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
Comments