나의 기록, 현진록

[Swift] 15.1 맵 본문

Programming/Swift

[Swift] 15.1 맵

guswlsdk 2021. 9. 14. 10:48
반응형

스위프트 프로그래밍 3판 - 야곰 지음

 

스위프트는 함수를 일급 객체로 취급합니다. 따라서 함수를 다른 함수의 전달인자로 사용할 수 있습니다. 매개변수로 함수를 갖는 함수를 고차함수라고 부르는데, 스위프트에 유용한 대표적인 고차함수로는 맵 필터 리듀스 등이 있습니다. 이번 장에서는 맵, 필터, 리듀스를 통해 데이터의 연산을 쉽게 실행하는 방법을 알아보겠습니다.

 

15.1 맵

맵은 자신을 호출할 때 매개변수로 전달된 함수를 실행하여 그 결과를 다시 반환해주는 함수입니다. 스위프트에서 맵은 배열, 딕셔너리, 세트, 옵셔널 등에서 사용할 수 있습니다. 조금 더 정확히 말하자면 스위프트의 Sequence, Collection 프로토콜을 따르는 타입과 옵셔널은 모두 맵을 사용할 수 있습니다. 

 

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

 

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

 

다음은 for-in 구문과 map 메서드의 비교이다.

 

let numbers = [0,1,2,3,4]

var doubledNumbers = [Int]()
var strings = [String]()

//for 구문 사용
for number in numbers{
    doubledNumbers.append(number*2)
    strings.append("\(number)")
}

print(doubledNumbers)
print(strings)

//map 메서드 사용
doubledNumbers = numbers.map({(number: Int) -> Int in 
    return number * 2
})
strings = numbers.map({(number: Int) -> String in
    return "\(number)"
})

print(doubledNumbers)
print(strings)

 

 

map 메서드를 사용하여 코드가 조금 더 간략해지긴 했지만, 우리가 배웠던 클로저 표현식을 사용하여 표현을 더 간략화해볼 수 있습니다.

 

let numbers = [0,1,2,3,4]

//기존 클로저 표현 사용
var doubledNumbers = numbers.map({(number: Int) -> Int in
    return number * 2
})
print(doubledNumbers)

//매개변수 및 반환 타입 생략
doubledNumbers = numbers.map({return $0 * 2})
print(doubledNumbers)

//반환 키워드 생략
doubledNumbers = numbers.map({$0 * 2})
print(doubledNumbers)

//후행 클로저 사용
doubledNumbers = numbers.map{$0 * 2}
print(doubledNumbers)

 

 

 

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

 

 

let evenNumbers = [0,2,4,6,8]
let oddNumbers = [0,1,3,5,7]
let multiplyTwo = {$0 * 2}

let doubledEvenNumbers = evenNumbers.map(multiplyTwo)
print(doubledEvenNumbers)

let doubledOddNumbers = oddNumbers.map(multiplyTwo)
print(doubledOddNumbers)

 

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

 

let alphabetDictionary: [String: String] = ["a":"A", "b":"B"]

var keys: [String] = alphabetDictionary.map{(tuple: (String, String)) ->
    String in
    return tuple.0
}

keys = alphabetDictionary.map{$0.0}

let values = alphabetDictionary.map{$0.1}
print(keys)
print(values)

var numberSet: Set<Int> = [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(resultInt) //경고가 발생하는 이유는 타입캐스팅에서 설명합니다.

let range: CountableClosedRange = (0...3)
let resultRange: [Int] = range.map{$0 * 2}
print(resultRange)

 

 

 

 

반응형

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

[Swift] 15.2 필터  (0) 2021.09.14
[Swift] 14.2 빠른 종료  (0) 2021.09.13
[Swift] 14.1 옵셔널 체이닝  (0) 2021.09.13
[Swift] Baekjoon 20300 서강근육맨  (0) 2021.09.09
[Swift] 13.4 값 획득  (0) 2021.09.07