-
[Swift] ๊ณ ์ฐจํจ์ (map, filter, reduce)Swift 2022. 1. 20. 22:30
Swift์ ํจ์๋ First-Class Citizen (์ผ๊ธ๊ฐ์ฒด)์ด๋ค.
๋ฐ๋ผ์ ํจ์๋
1. ๋ณ์๋ ์์์ ์ ์ฅ
2. ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ
3. ํจ์๋ ๋ฉ์๋์์ ๋ฆฌํด ํ ์ ์๋ค.
๊ณ ์ฐจ ํจ์ (Higher-order Function) ๋ ์ธ์๋ก ํจ์๋ฅผ ์ ๋ฌ๋ฐ๊ฑฐ๋, ํจ์๋ฅผ ๊ฒฐ๊ณผ๋ก ๋ฐํํ๋ ํจ์๋ฅผ ๋งํ๋ค.
Swift์์ ์ ๊ณตํ๋ ๋ํ์ ์ธ ๊ณ ์ฐจํจ์๋ก๋ ๋งต (map), ํํฐ (filter), ๋ฆฌ๋์ค (reduce)๊ฐ ์๋๋ฐ, ์ด์ ๋ํด์ ์์๋ณด๊ณ ์ ํ๋ค.
1. map (๋งต)
Swift์์ map์ ๋ฐฐ์ด (Array), ๋์ ๋๋ฆฌ (Dictionary), ์ (Set), ์ต์ ๋ ๋ฑ ์์ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ฐ, ์ฌ๊ธฐ์๋ ๋ฐฐ์ด์์ ์ฌ์ฉํ๋ map์ ๋ํด์ ์์๋ณด๊ณ ์ ํ๋ค.

map(_:) ์ ํด๋ก์ ๋ก ์ ๋ฌ๋ ์ํ์ค์ ์์๋ค์ ๋งตํํ ํ์ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์๋ก์ด ๋ฐฐ์ด๋ก ๋ง๋ค์ด์ ๋ฆฌํดํ๋ค.
๊ธฐ์กด ์ํ์ค ์์๋ค์ ๊ฐ์ ๋ณ๊ฒฝ๋์ง ์๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ map์ ๊ธฐ์กด์ ๋ฐ์ดํฐ๋ฅผ ๋ณํํ๋๋ฐ ๋ง์ด ์ฐ์ธ๋ค.
for-in ๊ตฌ๋ฌธ๊ณผ ๋น์ทํ๊ฒ ์ฌ์ฉ๋์ง๋ง, map ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ์ฝ๋๋ฅผ ๋ ๊ฐ๊ฒฐํ๊ฒ ๊ตฌํํ ์ ์๋ค.
๋ฐฐ์ด numArr์ ์ ์ฅ๋ ์์๋ค์ ๋ชจ๋ String์ผ๋ก ๋ฐ๊ฟ์ ์๋ก์ด ๋ฐฐ์ด์ ์ ์ฅํ๋ ค๊ณ ํ๋ค.
์๋ ์์๋ฅผ ๋ณด์.
for-in ๋ฌธ์ ์ฌ์ฉํ ์ฝ๋์ด๋ค.
numString ๋ฐฐ์ด์ ๋น ๋ฐฐ์ด๋ก ์์ฑํ ํ์, for-in ๋ฌธ ๋ด์์ append ๋ฉ์๋๋ฅผ ํตํด ์์ ์์ฑํ ๋ฐฐ์ด์ ์์๋ค์ ์ถ๊ฐํ๊ณ ์๋ค.
let numArr = [1, 2, 3, 4, 5] var numString: [String] = [] for num in numArr { numString.append("\(num)") } print(numString) // ["1", "2", "3", "4", "5"]์ ์ฝ๋๋ฅผ map ๋ฉ์๋๋ก ๊ตฌํํ๋ฉด ์๋์ ๊ฐ๋ค.
for-in ๋ฌธ์์๋ ๋ณ๋๋ก ๋น ๋ฐฐ์ด์ ์ด๊ธฐํํ์ฌ ์์ฑํด์ฃผ์์ง๋ง, map ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ๊ทธ๋ด ํ์๊ฐ ์๋ค.
map ๋ฉ์๋์ ๊ฒฐ๊ณผ ๊ฐ์ ๋ฐ๋ก ๋ฐฐ์ด์ ์ ์ฅํด์ฃผ๊ธฐ๋ง ํ๋ฉด ๋๋ค.
let numArr = [1, 2, 3, 4, 5] var numString = numArr.map { (number: Int) -> String in return "\(number)" } print(numString) // ["1", "2", "3", "4", "5"]๋ํ ์ ์ฝ๋๋ฅผ ๋ฌธ๋ฒ ์ต์ ํ๋ฅผ ์ด์ฉํ๋ฉด ๋ ๊ฐ๋จํ ๊ตฌํํ ์ ์๋ค.
let numArr = [1, 2, 3, 4, 5] var numString = numArr.map { "\($0)" } print(numString) // ["1", "2", "3", "4", "5"]2. filter (ํํฐ)
Swift์์ filter๋ ์ฃผ์ด์ง ์ํ์ค์ ์์๋ฅผ ์กฐ๊ฑด์ ๋ฐ๋ผ ์ถ์ถํ ํ์, ๊ทธ ๊ฐ๋ค์ ์์๋๋ก ๋ฐฐ์ด์ ํฌํจํ์ฌ ๋ฐํํ๋ค.

map๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์๋ก์ด ๋ฐฐ์ด๋ก ๋ฆฌํดํด์ค๋ค.
ํ์ง๋ง filter๋ map์ฒ๋ผ ๊ธฐ์กด์ ๊ฐ์ ๋ฐ๊พธ๋ ๊ฒ์ด ์๋๋ผ, ์ฃผ์ด์ง ์กฐ๊ฑด์ ๋ฐ๋ผ ๊ฐ์ ์ถ์ถํ์ฌ ์๋ก์ด ๋ฐฐ์ด๋ก ๋ฐํํ๋ค.
ํ๋ผ๋ฏธํฐ๋ isIncluded๋ก, ์ํ์ค์ ์์๋ฅผ ์ธ์๋ก ์ฌ์ฉํ๊ณ ๋ฐํํ ๋ฐฐ์ด์ ์์๋ฅผ ํฌํจํ ์ง์ ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ Boolean ๊ฐ์ ๋ฐํํ๋ ํด๋ก์ ์ด๋ค.
filter ํจ์์ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ๋๋ ํจ์์ ๋ฆฌํด ํ์ ์ Bool์ผ๋ก, ์กฐ๊ฑด์ ๋ฐ๋ผ ํฌํจํ ๊ฐ์ด๋ผ๋ฉด true๋ฅผ, ์๋๋ผ๋ฉด false๋ฅผ ๋ฐํํ๋ค.
์๋ ์์๋ filter(_:) ๋ฉ์๋๋ฅผ ์ด๋ฆ์ ๋ฌธ์๊ฐ 5์ ๋ฏธ๋ง์ธ ๊ฒ๋ค๋ง shortNames์ ์ ์ฅํด์ฃผ๊ณ ์๋ค.

๋ณต์ก๋๋ O(n)์ผ๋ก, ์ฌ๊ธฐ์ n์ ์ํ์ค์ ๊ธธ์ด๋ฅผ ์๋ฏธํ๋ค.
3. Reduce (๋ฆฌ๋์ค)
reduce๋ ์ฃผ์ด์ง closure๋ฅผ ์ฌ์ฉํ์ฌ ์ํ์ค์ ์์๋ฅผ ์กฐํฉํ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํดํ๋ค.

ํ๋ผ๋ฏธํฐ๋ initialResult์ nextPartialResult๊ฐ ์๋ค.
initialResult๋ ์ด๊ธฐ ๋์ ๊ฐ์ผ๋ก ์ฌ์ฉํ๋๋ฐ, ์ด๊ธฐ๊ฐ์ ์ง์ ํด์ค ์๋ ์๋ค.
closure๊ฐ ์ฒ์ ์คํ๋๋ฉด initialResult๊ฐ nextPartialResult๋ก ์ ๋ฌ๋๋ค.
nextPartialResult๋ ๋์ ๋ ๊ฐ๊ณผ ์ํ์ค์ ์์๋ฅผ ์๋ก์ด ๋์ ๊ฐ์ผ๋ก ๊ฒฐํฉํ๋ ํด๋ก์ ๋ก, nextPartialResult ํด๋ก์ ์ ๋ค์ ํธ์ถ์ ์ฌ์ฉ๋๊ฑฐ๋ caller์๊ฒ ๋ฐํ๋๋๋ฐ ์ฌ์ฉํ๋ค.
nextPartialResult์ ์ฒซ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ reduce apthemdml initialResult ํ๋ผ๋ฏธํฐ๋ฅผ ํตํด ์ ๋ฌ ๋ฐ์ ์ด๊ธฐ๊ฐ ๋๋ ์ด์ ํด๋ก์ ์ ๊ฒฐ๊ณผ๊ฐ์ด๊ณ , ๋ชจ๋ ์ํ๊ฐ ๋๋๋ฉด reduce์ ์ต์ข ๊ฒฐ๊ณผ๊ฐ์ด ๋๋ค.
nextPartialResult์ ๋๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ reduce ๋ฉ์๋๊ฐ ์ํํ๋ ๋ฐฐ์ด์ ์์๋ฅผ ์๋ฏธํ๋ค.
๋ฆฌํด๊ฐ์ ์ต์ข ์ ์ผ๋ก ๋์ ๋ ๊ฐ์ผ๋ก, ๋ง์ฝ ์ํ์ค๊ฐ ์์๊ฐ ์๋ค๋ฉด initialResult๊ฐ ๊ฒฐ๊ณผ์ด๋ค.
์ฆ, ํด๋ก์ ๊ฐ ๊ฐ ์์๋ฅผ ์ ๋ฌ๋ฐ์ ์ฐ์ฐํ ํ์, ์ด ๊ฐ์ ๋ค์ ํด๋ก์ ์คํ์ ์ํด ๋ฐํํ๋ฉฐ ์ํ์ค๋ฅผ ์ํํ๋ ํํ์ด๋ค.
reduce(_:_:) ๋ฉ์๋๋ ์ ์ฒด ์ํ์ค์ ์์ ์ค ๋จ์ผ ๊ฐ์ ์์ฑํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค.
์๋ฅผ ๋ค๋ฉด, ์ซ์๋ก ์ด๋ฃจ์ด์ง ๋ฐฐ์ด์์ ๊ทธ๋ค์ ํฉ ๋๋ ๊ณฑ์ ๊ตฌํ๊ธฐ ์ํด์ ์ด ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ค.
nextPartialResult ํด๋ก์ ๋ initialResult๋ก ์ด๊ธฐํ๋ ๋์ ๊ฐ๊ณผ ์ํ์ค์ ๊ฐ ์์๋ฅผ ์ฌ์ฉํ์ฌ ์์ฐจ์ ์ผ๋ก ํธ์ถ๋๋ค.
์๋ ์์ ๋ ์ซ์๋ก ์ด๋ฃจ์ด์ง ๋ฐฐ์ด์์ ๋ฐฐ์ด ์์๋ค์ ํฉ์ ์ฐพ๋ ๋ฐฉ๋ฒ์ด๋ค.

numbers.reduce(_:_:)๊ฐ ํธ์ถ๋๋ฉด ์๋์ ๊ฐ์ ๋จ๊ณ๊ฐ ๋ฐ์ํ๋ค.
1. nextPartialResult ํด๋ก์ ๋ initialResult๊ฐ 0์ธ ์ํ๋ก ํธ์ถ๋๋ค. numbers์ ์ฒซ๋ฒ์งธ ์์๋ 1์ด๊ธฐ ๋๋ฌธ์ ํฉ๊ณ 1์ ๋ฐํํ๋ค.
2. ํด๋ก์ ๊ฐ ์ด์ ํธ์ถ์ ๋ฆฌํด ๊ฐ๊ณผ ์ํ์ค์ ๊ฐ ์์์ ํจ๊ป ๋ค์ ๋ฐ๋ณต์ ์ผ๋ก ํธ์ถ๋๋ค.
3. ์ํ์ค ๋๊น์ง ๋ชจ๋ ํธ์ถํ๋ค๋ฉด, ๋ง์ง๋ง ํด๋ก์ ์์ ๋ฐํ๋ ๊ฐ์ด caller์๊ฒ ๋ฐํ๋๋ค.
๋ง์ฝ ์ํ์ค๊ฐ ์ด๋ค ์์๋ ๊ฐ์ง ์๋๋ค๋ฉด, nextPartialResult๋ ์ ๋ ์คํ๋์ง ์๊ณ , initialResult๊ฐ reduce(_:_:)๊ฐ ํธ์ถ ๊ฒฐ๊ณผ๊ฐ ๋๋ค.
๋ณต์ก๋๋ O(n)์ผ๋ก, ์ฌ๊ธฐ์ n์ ์ํ์ค์ ๊ธธ์ด๋ฅผ ์๋ฏธํ๋ค.
reduce ์์ 1
๋ฐฐ์ด nums์ ์๋ ์ซ์๋ค์ ๊ณฑ์ ๋ชจ๋ ๊ตฌํ๋ ๋ฐฉ๋ฒ

import UIKit var nums = [1, 2, 3, 4, 5] var a1 = nums.reduce(1, { (num1: Int, num2: Int) -> Int in return num1 * num2 }) // ํ๋ผ๋ฏธํฐ ํ์, ๋ฆฌํด ํ์ ์๋ต var a2 = nums.reduce(1, { (num1, num2) in return num1 * num2 }) // ํ๋ผ๋ฏธํฐ ์ด๋ฆ ์๋ต, in ํค์๋ ์๋ต, ํด๋ก์ ๋ฐ๋ ๋ด์ ํ๋ผ๋ฏธํฐ๋ฅผ shorthand Argument Name์ผ๋ก ๋ณ๊ฒฝ var a3 = nums.reduce(1, { return $0 * $1 }) // ๋จ์ผ return๋ฌธ์ด๋ฏ๋ก return ํค์๋ ์๋ต var a4 = nums.reduce(1, { $0 * $1 }) // ๋ง์ง๋ง ํ๋ผ๋ฏธํฐ์ด๋ฏ๋ก trailing closure๋ก ๋ณ๊ฒฝ var a5 = nums.reduce(1) { $0 * $1 } // ์ฐ์ฐ์๋ ์ค์ ์ฐ์ฐ์์ด๋ฏ๋ก ์ผ์ชฝ ๊ฐ์ด $0, ์ค๋ฅธ์ชฝ ๊ฐ์ด $1์์ ์ถ๋ก ํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ด ๋ณํ ๊ฐ๋ฅ var a6 = nums.reduce(1, *) print("=======") print(a1) print(a2) print(a3) print(a4) print(a5) print(a6) print("=======")reduce ์์ 2
๋ฐฐ์ด์ ์๋์์๋ฅผ ๋ชจ๋ ํฉ์ณ์ String์ผ๋ก ์ถ๋ ฅํ๋ ๋ฐฉ๋ฒ.
์ด ๋ result์ ํ์ ์ String์ด๋ค.

์ฝ๋ 
์ถ๋ ฅ ๊ฒฐ๊ณผ let arr = ["A", "B", "C", "D", "E", "F", "G", "H"] let result = arr.reduce("์์!\n", { print($0) return $0 + "\($1)" }) print(result)'Swift' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Swift] init(_:radix:) (0) 2022.02.02 [Swift] ํจ์ํ ํ๋ก๊ทธ๋๋ฐ (Functional Programming) (0) 2022.01.21 [Swift] ๋จ๋ฝ ํ๊ฐ (Short-circuit Evaluation), Side Effect (0) 2022.01.20 [Swift] zip(_:_:) (0) 2022.01.14 [Swift] Objected Oriented Programming in Swift (raywenderlich ๋ฒ์ญ) (0) 2022.01.13