Swift- 고차함수

아토시스·2023년 12월 5일
0

Swift

목록 보기
12/14

Map

  • 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)

map 메서드와 for-in 구문

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

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

Reduce

  • reduce는 줄이다 라는 뜻이지만 결합 기능을 하는 메서드이다.
  • 컨테이너의 내부의 요소들을 하나로 합치는 기능을 하는 고차 함수이다.
  • 배열의 모든 값을 전달 인자로 전달받아 클로저의 연산 결과로 합해주게 된다.

Swift에서의 reduce 형태(두 가지)

  • 첫 번째, 클로저가 각 요소를 전달받아 연산한 후 값을 다음 클로저 실행을 위해 반환하며 컨테이너를 순환하는 형태. 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
*/
profile
오늘보다 더 나은 내일이 되길 바라며

0개의 댓글