Starbucks Caramel Frappuccino
본문 바로가기
  • 그래 그렇게 조금씩
iOS Developer/Swift

고차함수 ( Higher-order Function)_ map, filter, reduce

by Toughie 2023. 4. 4.

 

스위프트에서 함수일급시민(일급객체_First Class Citizen)이기 때문에

함수의 파라미터로 전달 될 수 있고, 함수의 결과값으로 return 할 수도 있다.

 

고차함수는 함수를 파라미터로 쓰거나, 함수의 결과로 함수를 리턴하는 함수이다.

(input과 output이 다 함수일 수 있음_함수는 일급시민이니까)

 

대표적인 고차함수에는(다른 언어에도 대부분  정의 되어 있음)

map, filter, reduce, forEach, compactMap, flatMap이 있는데

먼저 기본인 map, filter, reduce에 대해 알아보고자 한다.

 

배열, 딕셔너리, 셋과 같은 컬렉션 타입에서 많이 쓰고

대부분 배열에서 자주 쓰는 경우가 많았다.

 

map

시간복잡도 O(n)

Returns an array containing the results of mapping the given closure over the sequence’s elements.

배열의 아이템을 매핑해서(변형해서) 새로운 배열을 리턴하는 함수.

 

정의

func map<T>(_ transform: (Self.Element) throws -> T) rethrows -> [T]

파라미터

transform
A mapping closure. transform accepts an element of this sequence 
as its parameter and returns a transformed value of the same or of a different type.

Array.map { }

 

예시코드

let cast = ["Vivien", "Marlon", "Kim", "Karl"]
let lowercaseNames = cast.map { $0.lowercased() }
// 'lowercaseNames' == ["vivien", "marlon", "kim", "karl"]
let letterCounts = cast.map { $0.count }
// 'letterCounts' == [6, 6, 3, 4]

위 코드에서 $0은 아래 반복문에서의 item과 같다. (배열의 각 요소를 순차적으로)

for item in cast {

. . .

}

"Vivien"부터 소문자로 매핑해서 전부 소문자로 바뀐 새로운 배열을 리턴하는 것이다.

(.map에서 리턴된 배열을  lowercaseNames 상수에 할당)

letterCounts는 cast 배열의 각각 아이템의 개수로 이루어진 새로운 배열이다.

 

배열의 값에 동일한 값을 더하거나,빼거나, 곱하거나, 나누거나..

데이터 변형이 필요할 때 사용할 수 있다.

 

filter

시간복잡도 O(n)

Returns an array containing, in order, 
the elements of the sequence that satisfy the given predicate.

클로저에서 제시하는 조건에 부합하는 아이템들로 이루어진 새로운 배열을 리턴

 

정의

func filter(_ isIncluded: (Self.Element) throws -> Bool) rethrows -> [Self.Element]

파라미터

isIncluded
A closure that takes an element of the sequence as its argument
and returns a Boolean value indicating whether the element should be included in the returned array.

Array.filter { }

 

예시코드

let cast = ["Vivien", "Marlon", "Kim", "Karl"]
let shortNames = cast.filter { $0.count < 5 }
print(shortNames)
// Prints "["Kim", "Karl"]"

cast 배열의 아이템 중에서 글자수가 5개 미만인 아이템들로만 이루어진 새로운 배열을 shortNames 상수에 할당.

짝수, 홀수, ~의 배수 등을 구할 때 유용하다.

reduce

시간복잡도 O(n)

Returns the result of combining the elements of the sequence using the given closure.

클로저의 결합방식에 따라 배열의 아이템을 결합해서 결과값을 리턴

 

정의

func reduce<Result>(
    _ initialResult: Result,
    _ nextPartialResult: (Result, Self.Element) throws -> Result
) rethrows -> Result

 

파라미터

initialResult
The value to use as the initial accumulating value.
initialResult is passed to nextPartialResult the first time the closure is executed.

nextPartialResult
A closure that combines an accumulating value 
and an element of the sequence into a new accumulating value,
to be used in the next call of the nextPartialResult closure or returned to the caller.

initialResult(값을 합치기_축적_)하기 위한 초기값.

클로저가 실행되면 initialResult가 nextPartialResult로 전달됨.

 

nextPartialResult

initialResult를 받아 계속 값을 축적하는 클로저

 

리턴

마지막에 축적된 값. 만약 아이템이 없는 빈 배열이라면 initialResult가 반환됨.

 

예시코드

let numbers = [1, 2, 3, 4]
let numberSum = numbers.reduce(0, { x, y in
    x + y
})
// numberSum == 10

여기서 initialResult는 0, 

nextPartialResult는 클로저 부분이다. { x, y in x + y }

먼저 0(초기값)이 클로저로 전달된다 (x == 0)

그다음 numbers 배열에서 맨 처음 아이템인 1이 y

둘이 더해진 값이 initialResult가 된다. (지금은 1)

이 1이 다시 x로 가고, numbers배열의 2가 y로 간다.

둘이 합쳐진 3이 initialResult가 된다. 

3이 다시 x, numbers 배열의 3이 y

더해진 6이 initalResult

6이 x, numbers 배열의 4가 y

더해진 10이 initialResult

더이상 numbers 배열의 아이템이 없기 때문에

모든 배열이 더해진(축적된) 마지막 initialResult인 10을 반환하는 것이다.

 

후행클로저 문법 최적화를 하면 아래와 같은 형태로도 자주 쓰인다.(형태가 다양하다)

_클로저가 마지막 파라미터인 경우_

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

let numberSum = numbers.reduce(0, { x, y in
    return x + y
})

let numberSum = numbers.reduce(0) { x, y in x + y }

let numberSum = numbers.reduce(0) { $0 + $1 }

let numberSum = numbers.reduce(0, +)
//초기값 0, 각 배열의 요소를 0에다 계속 더하겠다.

 

학습소스

https://developer.apple.com/documentation/swift

 

Swift | Apple Developer Documentation

Build apps using a powerful open language.

developer.apple.com