Swift Higher-order Functions
map, reduce, filter, flatMap, compactMap, forEach, contains, removeAll, sorted, split
1. First-Class π©βπ»
1. First-Class Citizen
νλ‘κ·Έλλ° μΈμ΄ λμμΈμμ First-Class Citizen
(type, object, entity, value)μ λ€λ₯Έ entity
μμ
μ¬μ©ν μ μλ λͺ¨λ μμ
μ μ§μνλ entity
λ‘ λ€μκ³Ό κ°μ νΉμ§μ κ°λλ€.
- λͺ¨λ μμ΄ν μ ν¨μμ parameters(arguments)κ° λ μ μλ€
- λͺ¨λ μμ΄ν μ ν¨μμ return value κ° λ μ μλ€
- λͺ¨λ μμ΄ν μ μμ λλ λ³μμ ν λΉ λ μ μλ€
- λͺ¨λ μμ΄ν μ tested for equality κ° κ°λ₯νλ€
2. First-Class Function
Computer Science μμ νλ‘κ·Έλλ° μΈμ΄κ° ν¨μλ₯Ό First-Class Citizen
μΌλ‘ λ€λ£¨λ©΄,
First-Class Function
μ κ°μ§κ³ μλ€κ³ νλ€. μ΄κ²μ λ€μμ μλ―Ένλ€.
- ν¨μκ° λ€λ₯Έ ν¨μμ arguments λ‘ μ λ¬λ μ μλ€
- ν¨μλ₯Ό λ€λ₯Έ ν¨μμ return value λ‘ λ°νν μ μλ€
- ν¨μλ₯Ό μμ λλ λ³μμ ν λΉ νκ±°λ Data Structures μ μ μ₯ν μ μλ€
- ν¨μμ equality λΉκ΅κ° κ°λ₯νλ€
λν νλ‘κ·Έλλ° μ΄λ‘ μ λ°λΌ First-Class Function μ Anonymous Functions
(Function literals)λ₯Ό μꡬνκΈ°λ
νλ€. First-Class Function μ΄ μλ νλ‘κ·Έλλ° μΈμ΄μμ ν¨μμ μ΄λ¦μ νΉλ³ν μνκ° μλ€. Integer
νμ
μ λ³μλ₯Ό
λ€λ£¨λ― ν¨μ μμ Function
νμ
μ μΌλ° λ³μμ²λΌ μ·¨κΈλλ€.
First-Class Function
μFunctional Programming
μ νμμμμ΄λ©°,Higher-order Functions
λFunctional programming
μ νμ€κ³Όλ κ°λ€.
Higher-order Functions μ μλ‘ Map
ν¨μλ₯Ό μ΄ν΄λ³΄μ. Map ν¨μλ Function
κ³Ό list
λ₯Ό arguments
λ‘
μ·¨νλ©°, list μ κ° member μ ν¨μλ₯Ό μ μ© ν list
λ₯Ό λ°ννλ€.
let someIntArray: [Int] = [1, 2, 4, 5, 8, 11, 15]
let doubleIntArray: [Int] = someIntArray.map { $0 * 2 }
print(doubleIntArray) // [2, 4, 8, 10, 16, 22, 30]
μ¦, νλ‘κ·Έλλ° μΈμ΄κ°
Map
μ μ§μνλ €λ©΄, λ°λμ ν¨μκ° λ€λ₯Έ ν¨μμarguments
λ‘ μ λ¬λ μ μμ΄μΌ νλ€.
First-Class Function μ μ§μνλ νλ‘κ·Έλλ° μΈμ΄μμλ Nested Functions
λλ Anonymous Functions
κ°
body μΈλΆμ λ³μ(non-local variables)λ₯Ό μ°Έμ‘°νλ κ²μ΄ μμ°μ€λ¬μ΄ λ°λ©΄, κ·Έλ μ§ μμ μΈμ΄λ ν¨μλ₯Ό arguments
λ‘
μ λ¬νκ±°λ return value
λ‘ λ°ννλλ° μ΄λ €μμ΄ μλ€.
λ°λΌμ μ΄κΈ° Imperative languages
(λͺ
λ Ήν μΈμ΄)μμλ μ΄λ₯Ό ννΌνκΈ° μν΄ ν¨μλ₯Ό return types λ‘ νμ©νμ§ μμμ λ¬Όλ‘ ,
Nested Functions λ non-local variables λ±μ λͺ¨λ νμ©νμ§ μμλ€. μ΄λ¬ν μΈμ΄μμ ν¨μλ Second-Class citizen
μ΄λ€.
μ΄ν μ΅μ μΈμ΄μμ First-Class Function μ μ μ ν μ§μνκΈ° μν΄ ν¨μμ λν μ°Έμ‘°λ₯Ό bare function pointer λμ
Closure λ‘ μ²λ¦¬νκ²λμκ³ , λ°λΌμ Garbage Collection μμ νμ μμκ° λλ€.
First-Class Function
μ ν¨μμ λν μ°Έμ‘°λ₯Όbare function pointer
λμClosures
λ‘ μ²λ¦¬νλ€. λ°λΌμGarbage Collection
μ΄ λ°λμ νμνλ€.
μ°Έκ³ λ‘ C μΈμ΄μ κ°μ΄ ν¨μκ° First-Class Citizen μ΄ μλ μΈμ΄λ function pointers λλ delegates μ κ°μ κΈ°λ₯μ μ΄μ©ν΄ Higher-order function λ¬Έλ²μ μμ±ν μ μλλ‘ νλ€. νμ§λ§ μΈμ΄ μμ²΄κ° First-Class Function μ μ§μνλ κ²μ΄ μλλ―λ‘ First-Class Citizen μ΄ λλ κ²μ μλλ€.
2. Higher-order Function Examples π©βπ»
1. TypeScript
twice
μ plusThree
λΌλ ν¨μκ° μλ€.
const twice = (f: Function) => {
return (x: number) => f(f(x))
}
const plusThree = (i: number) => i + 3
twice ν¨μλ μλμ κ°μ΄ Body λ₯Ό κ°μΈλ { }
μ return
ν€μλλ₯Ό μλ΅ν μ μλ€.
const twice = (f: Function) => (x: number) => f(f(x))
const plusThree = (i: number) => i + 3
- plusThree:
number
νμ μargument
λ₯Ό λ°μ 3μ λν΄number
νμ μ λ°ννλ€.- twice:
Function
νμ μargument
λ₯Ό λ°μ(x: number) => f(f(x))
ν¨μλ₯Ό λ°ννλ€.f(x)
λ‘ μ λ¬λλ ν¨μλ<Number>(x: number) => number
νμ μ ν¨μμ΄λ©°, parameter μ return type μ΄ λμΌνλ―λ‘ μ¬κ·κ° κ°λ₯νλ€. λ°λΌμf(f(x))
λargument
λ‘ μ λ ₯λ ν¨μλ₯Ό μ¬κ·λ₯Ό μ΄μ©ν΄ 2λ² μ€ννλ ν¨μλ€.
μ°Έκ³ λ‘ TypeScript
λ ν¨μμ νμ
μ λͺ
μν λ λ€μ λ κ°μ§ λ°©μμ typealias
λ₯Ό μ¬μ©ν μ μλ€.
- GenericFunc
type GenericFunc = <Number>(x: number) => number const twice = (f: GenericFunc) => (x: number) => f(f(x))
- GenericType
type GenericType<Number> = (x: number) => number const twice = (f: GenericType<number>) => (x: number) => f(f(x))
λ ν¨μλ₯Ό chaining
ν΄ someFunction
μ΄λΌλ ν¨μλ₯Ό λ§λ€κ³ , μ΄λ₯Ό μ€νν΄λ³΄λ©΄ λ€μκ³Ό κ°λ€.
const twice = (f: Function) => (x: number) => f(f(x))
const plusThree = (i: number) => i + 3
const someFunction = twice(plusThree)
console.log(someFunction(7)) // 13 (7 + 3) + 3
console.log(someFunction(9)) // 15 (9 + 3) + 3
console.log(someFunction(12)) // 18 (12 + 3) + 3
2. Swift
1 ) Function Declarations
func twice(_ f: @escaping (Int) -> Int) -> (Int) -> Int {
return { (x: Int) in
f(f(x))
}
}
twice(_:) ν¨μλ μλμ κ°μ΄ arguments μ return ν€μλλ₯Ό μλ΅ν μ μλ€.
(TypeScript μ λ¬λ¦¬ Body λ₯Ό κ°μΈλ { }
λ μλ΅ν μ μλ€.)
func twice(_ f: @escaping (Int) -> Int) -> (Int) -> Int {
{ f(f($0)) }
}
μ twice μ parameter type κ³Ό return type μ΄ λ³΄κΈ° νλ€λ€λ©΄ typealias
λ₯Ό μ¬μ©ν μλ μ½λλ₯Ό 보λλ‘ νμ.
typealias IntToInt = (Int) -> Int
func twice(_ f: @escaping intToInt) -> intToInt {
{ f(f($0)) }
}
μ΄μ plusThree λ₯Ό μΆκ°νκ³ ν¨μλ₯Ό chaining
μμΌ Swift λ²μ μ someFunction
μ μμ±ν΄λ³΄μ.
func twice(_ f: @escaping (Int) -> Int) -> (Int) -> Int {
{ f(f($0)) }
}
func plusThree(_ i: Int) -> Int {
i + 3
}
let someFunction = twice(plusThree(_:))
print(someFunction(7)) // 13 (7 + 3) + 3
print(someFunction(9)) // 15 (9 + 3) + 3
print(someFunction(12)) // 18 (12 + 3) + 3
2 ) Function Expressions
μ 1κ³Ό λμΌν λ‘μ§μ Expressions λ°©μμΌλ‘ μμ±ν΄λ³΄μ.
let twice = { (f: @escaping (Int) -> Int) in
{ f(f($0)) }
}
μμλ λ³μμ νμ
μ 미리 μ§μ ν΄ twice λ₯Ό λ€μκ³Ό κ°μ΄ μμ±νλ κ²λ κ°λ₯νλ€.
let twice: (@escaping (Int) -> Int) -> (Int) -> Int = { f in
{ f(f($0)) }
}
λ§μ°¬κ°μ§λ‘ typealias
λ₯Ό μ¬μ©ν΄ λ€μκ³Ό κ°μ΄ μμ±ν μ μλ€.
typealias IntToInt = (Int) -> Int
let twice = { (f: @escaping intToInt) in
{ f(f($0)) }
}
typealias IntToInt = (Int) -> Int
let twice: (@escaping intToInt) -> intToInt = { f in
{ f(f($0)) }
}
λ§μ°¬κ°μ§λ‘ ν¨μλ₯Ό chaining
μμΌ Closures λ₯Ό μ΄μ©ν someFunction
μ μμ±ν΄λ³΄μ.
let twice: (@escaping (Int) -> Int) -> (Int) -> Int = { f in
{ f(f($0)) }
}
let plusThree: (Int) -> Int = { $0 + 3 }
let someFunction = twice(plusThree)
print(someFunction(7)) // 13 (7 + 3) + 3
print(someFunction(9)) // 15 (9 + 3) + 3
print(someFunction(12)) // 18 (12 + 3) + 3
3. Higher-order Functions π©βπ»
1. forEach
λ€μμ Swift documentation μ Instance Method forEach(_:)
μ μ€λͺ
μ΄λ€.
func forEach(_ body: (Self.Element) throws -> Void) rethrows
Link: Apple Developer Documentation
κ·Έλ¦¬κ³ forEach μ νΉμ§μ λ€μκ³Ό κ°λ€.
- Collection μ λͺ¨λ elements λ₯Ό μνν λΏ
Return Value
κ° μλ€. continue
,break
κ°μ Control Transfer Statements λ₯Ό μ¬μ©ν μ μλ€. μ€μ§return
λ§ μ¬μ© κ°λ₯νλ€.
Collection μ μννλ κ³ μ μ μΈ λ°©λ²μΌλ‘ For-In Loops κ° μλ€.
let numbers: [Int] = [2, 5, 3, 9, 11, 14]
for number in numbers {
number.isMultiple(of: 2) ? print("\(number) is even") : print("\(number) is odd")
}
forEach λ For-In Loops μ λμΌν λ‘μ§μ μνν μ μλ€.
numbers.forEach { $0.isMultiple(of: 2) ? print("\($0) is even") : print("\($0) is odd") }
2 is even
5 is odd
3 is odd
9 is odd
11 is odd
14 is even
forEach μ For-In Loops μ μ°¨μ΄μ
- For-In Loops λ body λ΄μμ
continue
,break
μ κ°μ Control Transfer Statements λ₯Ό μ¬μ©ν μ μλ€.
let anotherNumbers: [Int?] = [2, 5, nil, 9, 11, nil, 6, nil, 14]
for number in anotherNumbers {
guard let number = number else {
print("Found nil")
continue
}
print("The double of \(number) is \(number * 2)")
}
The double of 2 is 4
The double of 5 is 10
Found nil
The double of 9 is 18
The double of 11 is 22
Found nil
The double of 6 is 12
Found nil
The double of 14 is 28
let anotherNumbers: [Int?] = [2, 5, nil, 9, 11, nil, 6, nil, 14]
for number in anotherNumbers {
guard let number = number else {
print("Found nil")
break
}
print("The double of \(number) is \(number * 2)")
}
The double of 2 is 4
The double of 5 is 10
Found nil
- λ°λ©΄ forEach λ
return
λ§ μ¬μ© κ°λ₯νλ€.
anotherNumbers.forEach { number in
guard let number = number else {
print("Found nil")
continue // 'continue' is only allowed inside a loop
}
print("The double of \(number) is \(number * 2)")
}
anotherNumbers.forEach { number in
guard let number = number else {
print("Found nil")
return
}
print("The double of \(number) is \(number * 2)")
}
The double of 2 is 4
The double of 5 is 10
Found nil
The double of 9 is 18
The double of 11 is 22
Found nil
The double of 6 is 12
Found nil
The double of 14 is 28
- For-In Loops μ forEach λͺ¨λ ν¨μμ
Return Value
κ° μλ€.- For-In Loops μ forEach λ λΉμ·νμ§λ§, forEachλ
loops
κ° μλλ―λ‘continue
λbreak
κ³Ό κ°μ Control Transfer Statements λ₯Ό μ¬μ©ν μ μλ€.- μ€μ λ‘ forEach λ Collection μ μννμ§λ§ forEach μ
argument
λ‘ μ λ¬λλtrailing closure
μ μ μ₯μμλ μ¬λ¬ λ² νΈμΆλ λΏloops
κ° μλκΈ° λλ¬Έμ΄λ€.- λ°λΌμ, νμ¬ νΈμΆλ
closure
λ₯Ό μ’ λ£νκΈ° μνreturn
ν€μλλ§ νμ©λλ€. λν μ¬κΈ°μ μ¬μ©λλ return ν€μλλ νμ¬ νΈμΆλ closure λ₯Ό μ’ λ£νλ κ²μΌ λΏforEach μν μ체λ₯Ό μ’ λ£νμ§λ μλλ€
(forEach μμ return μ For-In Loops μ continue μ κ°μ μν μ νλ€.).
2. map
1 ) Array.map(_:)
λ€μμ Swift documentation μ Instance Method map(_:)
μ μ€λͺ
μ΄λ€.
func map<T>(_ transform: (Self.Element) throws -> T) rethrows -> [T]
Link: Apple Developer Documentation
map ν¨μλ κ°μ₯ μ λͺ
ν Higher-order Function μΌλ‘ Collection μ λͺ¨λ elements μ λ‘μ§μ μν ν
new Collection
μ λ°ννλ€.
λ€μμ κ°μ₯ κΈ°λ³Έμ μΈ map ν¨μμ μλμ΄λ€. Original Collection
μ λͺ¨λ elementsμ 2λ₯Ό κ³±ν λ€μ
new Collection
μ λ°ννλ€.
let numbers: [Int] = [2, 5, 3, 9, 11, 14]
var doubled: [Int] = [Int]()
doubled = numbers.map { $0 * 2 }
print(doubled) // [4, 10, 6, 18, 22, 28]
new Collectionμ λ°ννλ κ²μ΄λ―λ‘, Original Collectionκ³Ό Data Type
μ΄ κ°μ νμκ° μλ€.
let degrees = [20, 45, 180, 360, 185]
let rads = degrees.map { Double($0) * Double.pi / 180.0 }
let tenThousand: Double = pow(10, 4)
rads.forEach { print("\(round($0 * tenThousand) / tenThousand) radian") }
0.3491 radian
0.7854 radian
3.1416 radian
6.2832 radian
3.2289 radian
2 ) Set.map(_:)
Set μ map μ Array μ map κ³Ό κ°λ€.
let people: Set<String> = ["Thomasin McKenzie", "Anya Taylor-Joy", "Matt Smith", "Diana Rigg", "Rita Tushingham"]
let firstName = people.map { $0.split(separator: " ")[0] }
let lastName = people.map { $0.split(separator: " ")[1] }
print(firstName) // ["Anya", "Rita", "Thomasin", "Matt", "Diana"]
print(lastName) // ["Taylor-Joy", "Tushingham", "McKenzie", "Smith", "Rigg"]
3 ) Dictionary.map(_:)
Dictionary λ Key: Value ꡬ쑰μ΄κΈ° λλ¬Έμ Array λ Set κ³Όλ μ‘°κΈ λ€λ₯Έ λͺ¨μ΅μ 보μΈλ€.
let info: [String: String] = ["name": "andrew",
"city": "berlin",
"job": "developer",
"hobby": "computer games"]
let keys = info.map { $0.key }
let values = info.map { $0.value }
print(keys) // ["city", "name", "hobby", "job"]
print(values) // ["berlin", "andrew", "computer games", "developer"]
λ§μ½, map μμ key μ value λ₯Ό ꡬλΆνμ§ μκ³ μ κ·Όνλ©΄, tuple
λ‘ μ κ·Όνκ²λλ€.
let tupleData = info.map { $0 }
print(type(of: tupleData)) // Array<(key: String, value: String)>
print(type(of: tupleData[0])) // (key: String, value: String)
print(type(of: tupleData[0].key)) // String
print(type(of: tupleData[0].value)) // String
tupleData.forEach {
print($0)
}
(key: "job", value: "developer")
(key: "name", value: "andrew")
(key: "hobby", value: "computer games")
(key: "city", value: "berlin")
μμμ λ³Ό μ μλ―μ΄ info.map { $0 }
μ Return Type μ (key: String, value: String)
νμ
μ
tuple μ μ μ₯νλ λ°°μ΄μ λ§λ€μ΄ λ°ννλ€.
let updatedKeysAndValues = info.map { ($0.uppercased(), $1.capitalized) }
print(type(of: updatedKeysAndValues)) // Array<(String, String)>
print(type(of: updatedKeysAndValues[0])) // (String, String)
updatedKeysAndValues.forEach {
print($0)
}
("CITY", "Berlin")
("NAME", "Andrew")
("JOB", "Developer")
("HOBBY", "Computer Games")
λ€μκ³Ό κ°μ΄ label μ ν¬ν¨νλλ‘ κ°κ³΅νλ κ²λ κ°λ₯νλ€.
let anotherKeysAndValues = info.map { (list: $0.uppercased(), userInfo: $1.capitalized) }
print(type(of: anotherKeysAndValues)) // Array<(list: String, userInfo: String)>
print(type(of: anotherKeysAndValues[0])) // (list: String, userInfo: String)
anotherKeysAndValues.forEach {
print($0)
}
(list: "CITY", userInfo: "Berlin")
(list: "JOB", userInfo: "Developer")
(list: "NAME", userInfo: "Andrew")
(list: "HOBBY", userInfo: "Computer Games")
μ΄μ μ tuple μ Dictionary
μ initializer
λ₯Ό μ΄μ©ν΄ λ€μ Dictionary λ‘ λ§λ€μ΄λ³΄μ
let capitalizedInfo = Dictionary(uniqueKeysWithValues: anotherKeysAndValues)
print(type(of: capitalizedInfo)) // Dictionary<String, String>
print(capitalizedInfo) // ["NAME": "Andrew", "HOBBY": "Computer Games", "CITY": "Berlin", "JOB": "Developer"]
λλ μλμ λ°°μΈ reduce
λ₯Ό μ΄μ©νλ©΄ map
μ΄ λ°°μ΄μ λ°νν κ°μ κ·Έλλ‘ Higher-order Functions
μ
chaining
μ μ΄μ©ν΄ λ€μκ³Ό κ°μ΄ μμ±νλ κ²μ΄ κ°λ₯νλ€.
let capitalizedInfo = info.lazy
.map { ($0.uppercased(), $1.capitalized) }
.reduce(into: [String: String]()) { $0[$1.0] = $1.1 }
μ reduce
κ° μ΄λ»κ² μλνλ κ²μΈμ§ μμ§μ μ΄ν΄νκΈ°κ° μ΄λ €μΈ κ²μ΄λ€. reduce
μ λ§μ§λ§ argument
μ
trailing closure
μ λ΄λΆμμ $0
, $1.0
, $1.1
μ μΆλ ₯ν΄λ³΄λ©΄ λ€μκ³Ό κ°λ€.
let capitalizedInfo = info.lazy
.map { ($0.uppercased(), $1.capitalized) } // return tuple array
.reduce(into: [String: String]()) {
let str = """
$0: \($0)
$1.0: \($1.0), $1.1: \($1.1)
"""
print(str)
return $0[$1.0] = $1.1
}
$0: [:]
$1.0: HOBBY, $1.1: Computer Games
$0: ["HOBBY": "Computer Games"]
$1.0: NAME, $1.1: Andrew
$0: ["HOBBY": "Computer Games", "NAME": "Andrew"]
$1.0: JOB, $1.1: Developer
$0: ["HOBBY": "Computer Games", "NAME": "Andrew", "JOB": "Developer"]
$1.0: CITY, $1.1: Berlin
μ κ²½μ°λ map μμλ λ°μ΄ν°λ₯Ό κ°κ³΅λ§ νκ³ , reduce μμ λ°μ΄ν°λ₯Ό λͺ¨μλ€. κ·Έλ¦¬κ³ μ΄λ₯Ό lazy λ₯Ό μ΄μ©ν΄μ chaining νλ€.
μ¬μ€ reduce κ° λλΆλΆμ μμ μμ Integer Array
λ₯Ό μ¬μ©ν΄ κ°μ λνκ±°λ κ³±νλ λ±μ λ‘μ§μ 보μ¬μ£Όλ€λ³΄λ Collection μ΄
μλ λ¨μΌ κ°μ λ°νν΄μΌ νλ κ²μΌλ‘ μκ°νκΈ° μ½μ§λ§ λ¨μΌ Array λλ λ¨μΌ Dictionary μ κ°μ΄ νλμ Collection νμ
μμ
κ°μ λμ μμΌ λ°ννλ κ² μμ κ°λ₯νλ€(Array, Dictionary μμ νλμ κ°μ΄λ€.).
λ°λΌμ λ¨ ν λ²μ reduce λ‘ λ€μκ³Ό κ°μ΄ μμ±νλ κ²λ κ°λ₯νλ€.
let capitalizedInfo = info.lazy
.map { ($0.uppercased(), $1.capitalized) }
.reduce(into: [String: String]()) { $0[$1.0] = $1.1 }
// ["NAME": "Andrew", "JOB": "Developer", "HOBBY": "Computer Games", "CITY": "Berlin"]
let capitalizedInfo = info.reduce(into: [String: String]()) {
$0[$1.key.uppercased()] = $1.value.capitalized
}
// ["NAME": "Andrew", "JOB": "Developer", "HOBBY": "Computer Games", "CITY": "Berlin"]
4 ) Dictionary.mapValues(_:)
μΌλ°μ μΌλ‘ Dictionary
λ₯Ό μ¬μ©ν λ Key
λ λ³κ²½νμ§ μλλ€. μ΄λ΄ λ μ μ©ν ν¨μκ° mapValues
λ€.
let updatedValues = info.mapValues { $0.capitalized }
print(updatedValues) // ["hobby": "Computer Games", "job": "Developer", "city": "Berlin", "name": "Andrew"]
Dictionay
μmap
ν¨μλ₯Ό μ μ©ν λ μ μ©ν κ°κ°μ case λ₯Ό μ 리νλ©΄ λ€μκ³Ό κ°λ€.
- someDictionary.map : (μ΅μ’ κ²°κ³Όλ¬Όμ΄
Array<Any>
) λλ (Key
μ λ³κ²½μ΄ νμν λ)
(Dictionary λ‘ λ°ννκΈ° μν΄μλ μΆκ°λ‘ reduce κ° νμνλ€.)- someDictionary.reduce : (μ΅μ’ κ²°κ³Όλ¬Όμ΄
Dictionary
) & (Key
μ λ³κ²½μ΄ νμν λ)someDictionary.mapValues : (μ΅μ’ κ²°κ³Όλ¬Όμ΄
Dictionary
) & (Value
μ λ³κ²½λ§ νμν λ)- someDictionary.keys.map : (μ΅μ’ κ²°κ³Όλ¬Όμ΄
Array
) & (Key
λ§ νμν λ)- someDictionary.values.map : (μ΅μ’ κ²°κ³Όλ¬Όμ΄
Array
) & (Value
λ§ νμν λ)
3. compactMap
Collection μ΄ nil
μ ν¬ν¨νκ³ μλ κ²½μ° μ μ©νκ² μ¬μ©ν μ μλ, map κ³Ό λ§€μ° μ μ¬ν compactMap
μ΄ μλ€.
λ€μμ Swift documentation μ Instance Method compactMap(_:)
μ μ€λͺ
μ΄λ€.
func compactMap<ElementOfResult>(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
Link: Apple Developer Documentation
1 ) Optional Collection with map
let numbersWithNil: [Int?] = [5, 15, nil, 3, 9, 12, nil, nil, 17, nil]
μ nil
μ΄ ν¬ν¨λ Collectionμ map
ν¨μλ₯Ό μ¬μ©ν΄λ³΄μ.
let doubledNums = numbersWithNil.map { $0 * 2 } // error: value of optional type 'Int?' must be unwrapped to a value of type 'Int'
numbersWithNil
μ΄ μ μ₯νλ λ°μ΄ν° νμ
μ Int?
μ΄λ―λ‘ unwrapping
μ νμ§ μμΌλ©΄ μ°μ μ°μ°μ ν μ μμ΄μ μλ¬κ° λ°μνλ€.
let doubledNums = numbersWithNil.map { $0! * 2 } // Fatal error: Unexpectedly found nil while unwrapping an Optional value
unwrapping μ νμ§λ§ λ λ€λ₯Έ μλ¬κ° λ°μνλ€. λ°λ‘ Collection μ element κ° nil
μΈ μκ° nil! * 2
μ°μ°μ μλν΄ Runtime Error κ° λ°μνλ€.
λ°λΌμ λ€μκ³Ό κ°μ΄ Type-Safe
ν μ½λλ₯Ό μν΄ nil check λ₯Ό ν΄μ€μΌνλ€.
let doubledNums = numbersWithNil.map { (number) -> Int? in
guard let number = number else { return nil }
return number * 2
}
μ λ‘μ§μ Ternary Operator
λ₯Ό μ΄μ©ν΄ μ΅μ ν νλ©΄ λ€μκ³Ό κ°λ€.
let doubledNums = numbersWithNil.map { $0 != nil ? $0! * 2 : nil }
print(type(of: doubledNums)) // Array<Optional<Int>>
print(doubledNums) // [Optional(10), Optional(30), nil, Optional(6), Optional(18), Optional(24), nil, nil, Optional(34), nil]
2 ) Optional Collection with compactMap
let doubledNumsWithoutNil = numbersWithNil.compactMap { $0 != nil ? $0! * 2 : nil }
print(type(of: doubledNumsWithoutNil)) // Array<Int>
print(doubledNumsWithoutNil) // [10, 30, 6, 18, 24, 34]
compactMap μ μ¬μ©νλλΌλ Type-Safe
ν μ½λλ₯Ό μν΄ nil check
λ λ°λμ ν΄μ€μΌνλ€(filter λ€μμ map μ
chaining νλ κ²μ²λΌ compactMap λ€μμ map μ chaining ν΄λ λμ§λ§, κ·Έλ¬λ©΄ κ΅³μ΄ compactMapμ μΈ
μ΄μ κ° μ€μ΄λ λ€).
νμ§λ§ Original Collection μ nil
μ κ·Έλλ‘ ν¬ν¨νλ map κ³Ό λ¬λ¦¬ compactMap μ Optional elementsλ₯Ό μ κ±°
νκ³ ,
unwrapping
λ Collection μ λ°ννλ€. λ°λΌμ, nil
μ μ«μλ§νΌ Collection μ κΈΈμ΄ μμ μ€μ΄λ λ€.
μ¦, compactMap
μ λ€μ μ½λλ₯Ό μμΆν κ²κ³Ό κ°λ€.
let doubledNumsWithoutNil = numbersWithNil
.map { $0 != nil ? $0! * 2 : nil }
.filter { $0 != nil }
.map { $0! }
print(type(of: doubledNumsWithoutNil)) // Array<Int>
print(doubledNumsWithoutNil) // [10, 30, 6, 18, 24, 34]
3 ) Optional Collection with default value
Optional Collection μ΄λΌκ³ 무쑰건 compactMap μ μ¬μ©ν΄μλ μ λλ€. nil
μ μ κ±°νμ§ μκ³ λ¨κ²¨λκ±°λ,
default value
μ²λ¦¬λ₯Ό ν΄μΌν μλ μλ€.
λ§μ½ nil
μ default value λ‘ μ²λ¦¬νλ©΄ λ°νλ Collection μ λ μ΄μ nil
μ ν¬ν¨νμ§ μμΌλ―λ‘ compactMap κ³Ό
map μ λμΌνκ² μλνλ€. λ°λΌμ μ΄ κ²½μ° κ΅³μ΄ compactMap μ μΈ νμκ° μλ€. map μμ nil
μ΄ μ κ±°λ
new Collection
μ λ°ννλ―λ‘, Swift λ μ΄λ₯Ό μΆλ‘ ν΄ unwrapping
λ Collection μ λ°ννλ€.
let withDefaultValue = numbersWithNil.compactMap { $0 != nil ? $0! * 2 : -1 }
print(type(of: withDefaultValue)) // Array<Int>
print(withDefaultValue) // [10, 30, -1, 6, 18, 24, -1, -1, 34, -1]
let withDefaultValue = numbersWithNil.map { $0 != nil ? $0! * 2 : -1 }
print(type(of: withDefaultValue)) // Array<Int>
print(withDefaultValue) // [10, 30, -1, 6, 18, 24, -1, -1, 34, -1]
map μ μ¬μ©νμ§λ§
nil
μdefault value
λ‘ μ²λ¦¬νκΈ° λλ¬Έμ Swift λ μ΄λ₯Ό μΆλ‘ ν΄unwrapping
λ new Collection μ λ°ννλ€.
λ¨, default value λ₯Ό μ¬μ©ν λ μ£Όμν΄μΌ ν κ²μ μ£Όμ΄μ§ default value κ° μ 체 μ± λλ ꡬν μ€μΈ λ‘μ§μside effect
λ₯Ό μΌμΌν€μ§ μλ κ°μ μ νν΄μΌνλ€.
4 ) Application of compactMap
compactMap μ κ°μ₯ μ μ©ν μ μ λ€μκ³Ό κ°μ μ½λλ₯Ό λ§€μ° κ°λ΅νκ² ννν μ μλ€λ κ²μ΄λ€.
let coins = ["1", "5", "$", "10", "6"]
var validCoins: [Int] = []
for coin in coins {
guard let coin = Int(coin) else { continue }
validCoins.append(coin)
}
print(validCoins) // [1, 5, 10, 6]
let validCoins = coins.compactMap { Int($0) }
print(validCoins) // [1, 5, 10, 6]
μ΄κ² μ λΆλ€! Type-Safe
ν μ½λλ₯Ό μν΄ μ¬μ©λλ guard let
, if let
μ μ¬μ©ν μ¬λ¬ μ€μ μ½λλ₯Ό
compactMap μ λ§€μ° κ°λ¨νκ² μ²λ¦¬νλ€.
compactMap μ
.map { (YOUR_TYPE_SAFE_CODE) } .filter { $0 != nil } .map { $0! }
λ₯Ό μμΆν κ²μ΄λ€. λ°λΌμ, Collection μμnil
μ μ κ±°νκ³non-nil
λ§ μ»κ³ μ ν λ μ μ©νλ€.
4. flatMap
λ€μμ Swift documentation μ Instance Method flatMap(_:) μ μ€λͺ μ΄λ€.
func flatMap<SegmentOfResult>(_ transform: (Self.Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
Link: Apple Developer Documentation
flatMap μ 2D Array
λ₯Ό 1D Array
λ‘ λ°κΎΌλ€. μ¦, Collection
μμ Collection
μ΄ μμ λ μ μ©νλ€.
1 ) 2D Array to 1D Array
let marks = [[3, 4, 5], [2, 5, 3], [1, 2, 2], [5, 5, 4], [3, 5, 3]]
- For-In Loops
var allMarks: [Int] = []
for marksArray in marks {
allMarks += marksArray
}
print(allMarks) // [3, 4, 5, 2, 5, 3, 1, 2, 2, 5, 5, 4, 3, 5, 3]
- flatMap
let allMarks = marks.flatMap { $0 }
print(allMarks) // [3, 4, 5, 2, 5, 3, 1, 2, 2, 5, 5, 4, 3, 5, 3]
2 ) Application of flatMap
μ΄λ²μλ μ 2D Array μ λͺ¨λ elements μ ν©μ ꡬν΄λ³΄μ. μΌλ°μ μΌλ‘ μ΄λ¬ν ꡬ쑰μμλ μ΄μ€ For-In Loops λ₯Ό μ¬μ©νκ²λλ€.
- For-In Loops
var sum: Int = 0
for marksArray in marks {
for element in marksArray {
sum += element
}
}
print(sum) // 52
- flatMap
let sum = marks
.flatMap { $0 }
.reduce(0) { $0 + $1 }
print(sum) // 52
3 ) Composite case
μ΄λ²μλ 2D Collection μ nil
μ΄ ν¬ν¨λ κ²½μ°λ₯Ό μκ°ν΄λ³΄μ.
let marksWithNil = [[3, nil, 5], [2, 5, nil], [1, 2, 2], [5, 5, 4], [nil, 5, 3]]
- For-In Loops
μΌλ°μ μΌλ‘ For-In Loops λ₯Ό μ΄μ©νλ©΄ λ€μ λ°©λ² μ€ νλλ₯Ό μ¬μ©ν κ²μ΄λ€.
for marksArray in marksWithNil {
for element in marksArray {
anotherSum += element ?? 0
}
}
print(anotherSum) // 42
for marksArray in marksWithNil {
for element in marksArray {
guard let element = element else { continue }
anotherSum += element
}
}
print(anotherSum) // 42
var anotherSum: Int = 0
for marksArray in marksWithNil {
for element in marksArray where element != nil {
anotherSum += element!
}
}
print(anotherSum) // 42
- flatMap
flatMap
μ λ€λ₯Έ Higher-order Functions
μ ν¨κ» chaining
νλ©΄ λ§€μ° κ°λ¨νκ³ κΉλν μ½λλ‘ κ΅¬νν μ μλ€.
let anotherSum = marksWithNil
.flatMap { $0 }
.reduce(0) { $0 + ($1 ?? 0) }
print(anotherSum) // 42
let anotherSum = marksWithNil.lazy
.flatMap { $0 }
.filter { $0 != nil }
.reduce(0) { $0 + $1! }
print(anotherSum) // 42
let anotherSum = marksWithNil.lazy
.flatMap { $0 }
.compactMap { $0 }
.reduce(0) { $0 + $1 }
print(anotherSum) // 42
5. filter
λ€μμ Swift documentation μ Instance Method filter(_:)
μ μ€λͺ
μ΄λ€.
func filter(_ isIncluded: (Self.Element) throws -> Bool) rethrows -> [Self.Element]
Link: Apple Developer Documentation
filter ν¨μλ Higher-order Functions μ€ map κ³Ό ν¨κ» κ°μ₯ λ§μ΄ μ¬μ©λλ ν¨μλ€.
filter λ Collection μ λͺ¨λ elements μ λ‘μ§μ μν ν Bool
condition μ΄ true
μΈ κ°μ λν΄
new Collection
μ λ°ννλ€.
1 ) Filter some condition
μλ λ°°μ΄ words μμ λ¬Έμ o
λ₯Ό ν¬ν¨νλ elements λ§ κ°λ μ λ°°μ΄μ λ§λ€μ΄λ³΄μ.
let words: [String] = ["room", "home", "train", "green", "heroe"]
- For-In Loops
Collection μ μννλ©° κ²°κ³Όλ₯Ό κ³μ°ν΄ λ΄μ λ³μλ₯Ό μμ±νκ³ , For-In Loops λ₯Ό μ΄μ©νλ€.
var wordsWithO: [String] = []
for word in words {
if word.contains("o") {
wordsWithO.append(word)
}
}
λ§μ½ κ²°κ³Όλ₯Ό λ³μκ° μλ μμμ λ΄κ³ μΆλ€λ©΄ μ΄λ»κ² ν΄μΌν κΉ? μ°μ λ³μ temp λ₯Ό λ§λ€μ΄ μ μ₯νλ€. κ·Έλ¦¬κ³ κ³μ°μ΄ λλ ν μ΄ λ³μλ₯Ό μμ wordsWithO μ ν λΉνλ©΄ κ°μ΄ 볡μ¬λλ€.
var temp: [String] = []
for word in words {
if word.contains("o") {
temp.append(word)
}
}
let wordsWithO: [String] = temp
νμ§λ§ μ λ°©μμ μ’μ 보μ΄μ§ μλλ€. μ°λ¦¬λ μ΄ λ¬Έμ λ₯Ό closure
λ₯Ό μ΄μ©ν΄ ν΄κ²°ν μ μλ€.
let closure = {
var wordsWithO: [String] = []
for word in words {
if word.contains("o") {
wordsWithO.append(word)
}
}
return wordsWithO
}
let wordsWithO: [String] = closure()
λ§μ½ closure κ° μΌνμ±μΌλ‘ μ¬μ© ν μλ©Έλ κ±°λΌλ©΄ λ€μκ³Ό κ°μ΄ anonymous
λ‘ λ§λ€ μ μλ€.
let wordsWithO: [String] = {
var wordsWithO: [String] = []
for word in words {
if word.contains("o") {
wordsWithO.append(word)
}
}
return wordsWithO
}()
- filter
νμ§λ§ filter λ₯Ό μ΄μ©νλ©΄ μ closure λ³΄λ€ λ κ°κ²°νκ² μ½λλ₯Ό μμ±ν μ μλ€.
let wordsWithO: [String] = words.filter { $0.contains("o") }
print(wordsWithO) // ["room", "home", "heroe"]
2 ) Filter nil
nil
κ°μ νν°λ§ ν λλ λ€μκ³Ό κ°μ μ°¨μ΄κ° μμΌλ μ£Όμν΄μΌνλ€.
μλ λ°°μ΄ numbersWithNil μμ nil
μ΄ μλ κ°μ ν©μ ꡬν΄λ³΄μ.
let numbersWithNil = [1, 2, nil, 5, nil, 32, 7]
μ°μ numbersWithNil μ κ°κ° filter
, compactMap
, map
μ μ΄μ©ν΄ nil
μ μ κ±°ν΄λ³΄μ.
print(numbersWithNil.filter { $0 != nil }) // [Optional(1), Optional(2), Optional(5), Optional(32), Optional(7)]
print(numbersWithNil.compactMap { $0 }) // [1, 2, 5, 32, 7]
print(numbersWithNil.map { $0 != nil ? $0! : 0 }) // [1, 2, 0, 5, 0, 32, 7]
- filter λ
nilμ μ κ±°
νμ§λ§ Optional μ unwrapping νμ§λ λͺ» νλ€.- compactMap μ
nilμ μ κ±°
νκ³ , Optional μunwrapping
νλ€.- map μ μ μ ν
default value
μ ν¨κ» μ¬μ©νλ©΄,nil
μ μ κ±°νμ§λ λͺ» νμ§λ§ Optional μunwrapping
ν μ μλ€.
(μ΄λ default valueλside effect
λ₯Ό μΌμΌν€μ§ μμμΌνλ€)
μ¬μ€ μλμ μΌλ‘ nil
μ νΉμ ν default value
λ‘ λ°κΎΈλ €λ κ²μ΄ μλλΌλ©΄ map case λ μ’μ§ λͺ» ν λ°©λ²μ΄λ€. μ κ°μ λνκΈ° μν΄
0
μ΄λΌλ κ°μ default value λ‘ μ£Όμμ§λ§ λ§μ½ κ³±νκΈ°λ‘ λ³κ²½λλ€λ©΄? default value λ₯Ό λ€μ 1
λ‘ λ³κ²½ν΄μ€μΌνλ€.
μ΄λ° μ½λλ μ μ°μ±(μ¬μ¬μ©μ±)μ΄ λ¨μ΄μ§ λΏ μλλΌ λΆνμν κ°μ κ³μ κ°μ§κ³ λ€λλ―λ‘ μ±λ₯λ μ’μ§ λͺ» νλ€. λν μ½λκ° κΈΈμ΄μ§κ±°λ μ½λλ₯Ό
μμ±ν μ΄ν μ μ§λ³΄μ ν λ human error
λ₯Ό λ°μμν€λ μμΈμ΄ λ κ°λ₯μ±λ λλ€.
let sumWithFilter = numbersWithNil.lazy
.filter { $0 != nil }
.reduce(0) { $0 + $1! }
let sumWithCompactMap = numbersWithNil.lazy
.compactMap { $0 != nil ? $0 : nil }
.reduce(0) { $0 + $1 }
let sumWithReduce = numbersWithNil.reduce(0) { $0 + ($1 ?? 0) }
print("sumWithFilter: \(sumWithFilter)")
print("sumWithCompactMap: \(sumWithCompactMap)")
print("sumWithReduce: \(sumWithReduce)")
sumWithFilter: 47
sumWithCompactMap: 47
sumWithReduce: 47
3 ) Compare with TypeScript
TypeScript λ compactMap ν¨μκ° μλ€. λ°λΌμ μ΄λ° κ²½μ°λ filter λ₯Ό λ€λ₯Έ Higher-order Functions
μ
κ²°ν©ν΄ λ€μκ³Ό κ°μ΄ ꡬννλ€.
const numbersWithNil: (number | null | undefined)[] = [1, 2, null, 5, undefined, 32, 7]
console.log(numbersWithNil.filter(value => value !== null && value !== undefined)) // [ 1, 2, 5, 32, 7 ]
console.log(numbersWithNil.filter(value => !!value)) // [ 1, 2, 5, 32, 7 ]
const sumWithFilter = numbersWithNil.filter(value => !!value)
.reduce((prev, curr) => prev! + curr!, 0)
const sumWithReduce = numbersWithNil.reduce((prev, curr) => prev! + (curr ?? 0), 0)
console.log(`sumWithFilter: ${sumWithFilter}`)
console.log(`sumWithReduce: ${sumWithReduce}`)
sumWithFilter: 47
sumWithReduce: 47
λλ βlodashβ μ κ°μ Array λ₯Ό λ€λ£¨κΈ° μ½κ² λμμ£Όλ library λ₯Ό μ¬μ©νλ€.
import {compact} from 'lodash';
console.log(compact(numbersWithNil)) // [ 1, 2, 5, 32, 7 ]
const sumWithCompact = compact(numbersWithNil)
.reduce((prev, curr) => prev + curr)
console.log(`sumWithCompact: ${sumWithCompact}`)
sumWithCompact: 47
νν°λ§ νλ €λ κ°μ΄
nil
μ΄κ³ , μ΄nil
μ λ²λ¦΄κ±°λΌλ©΄ Swift λ compactMap μ built-in λ©μλλ‘ μ 곡νλ―λ‘ μ½λμ κ°λ μ±μ μν΄ μ‘°κ±΄μ΄ μΌμΉν κ²½μ° μ νμ©νλλ‘ νμ.
4 ) Application of filter
filter λ Primitive Types
λ₯Ό μ μ₯νλ Collection λΏ μλλΌ Class
, Structure
λ₯Ό μ μ₯νλ Collection μλ
μ¬μ©μ΄ κ°λ₯νλ€.
struct Tester {
var name: String
var age: Int
}
let testers: [Tester] = [Tester(name: "John", age: 23),
Tester(name: "Lucy", age: 25),
Tester(name: "Tom", age: 32),
Tester(name: "Mike", age: 29),
Tester(name: "Hellen", age: 19),
Tester(name: "Jim", age: 35),
Tester(name: "Jamie", age: 30)]
μ΄λ¦μ΄ J
λ‘ μμνλ©΄μ λμ΄κ° 30μ΄ μ΄μμΈ μ§μμ μ°Ύλ μλ₯Ό 보μ.
let result: [Tester] = testers.filter { $0.name.prefix(1) == "J" && $0.age >= 30 }
result.forEach { print("\($0.name), \($0.age)") }
Jim, 35
Jamie, 30
6. reduce
λ€μμ Swift documentation μ Instance Method reduce(_:_:)
μ μ€λͺ
μ΄λ€.
func reduce<Result>(
_ initialResult: Result,
_ nextPartialResult: (Result, Self.Element) throws -> Result
) rethrows -> Result
Link: Apple Developer Documentation
forEach λ map μ΄ new Collection
μ λ°ννλ κ²κ³Ό λ¬λ¦¬ reduce λ λͺ¨λ elements λ₯Ό μννλ©° κ° elements λ₯Ό
κ²°ν©νλ λ‘μ§μ ν΅ν΄ one result
λ₯Ό λ°ννλ€.
μΈμ΄λ μ¬μ΄νΈμ λ°λΌ Higher-order Functions μ reduce μ€λͺ μ 보면
- (initialResult, Closure[Result, Element])
- (initialValue, Function[previousValue, currentValue])
- (initialValue, Function[accumulator, currentValue])
μ΄λ°μμΌλ‘ parameters μ μ΄λ¦μ λ€λ₯΄μ§λ§ λͺ¨λ λμΌν reduce λ₯Ό ꡬννλ€.
μλ λ°°μ΄μ ν©κ³Ό κ³±μ ꡬν΄λ³΄μ.
let numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- For-In Loops
let sum: Int = {
var sum: Int = 0 // initialValue is '0'
for number in numbers {
sum += number
}
return sum
}()
let product: Int = {
var product: Int = 1 // initialValue is '1'
for number in numbers {
product *= number
}
return product
}()
print("sum: \(sum) product: \(product)") // sum: 55 product: 3628800
- reduce
reduce λ₯Ό μ΄μ©νλ©΄ λ€μκ³Ό κ°μ΄ λ§€μ° μ§§κ³ κ°λ¨ν λΏ μλλΌ κ°λ μ± λν μ’λ€.
let sum: Int = numbers.reduce(0, { (prev, curr) -> Int in prev + curr }) // initialValue is '0'
let product: Int = numbers.reduce(1, {(prev, curr) -> Int in prev * curr }) // initialValue is '1'
let sum: Int = numbers.reduce(0, { $0 + $1 })
let product: Int = numbers.reduce(1) { $0 * $1 }
let sum: Int = numbers.reduce(0, +)
let product: Int = numbers.reduce(1, *)
print("sum: \(sum) product: \(product)") // sum: 55 product: 3628800
7. contains
λ€μμ Swift documentation μ Instance Method contains(_:)
μ contains(where:)
μ μ€λͺ
μ΄λ€.
func contains(_ element: Self.Element) -> Bool
func contains(where predicate: (Self.Element) throws -> Bool) rethrows -> Bool
Link: Apple Developer Documentation contains(_:)
Link: Apple Developer Documentation contains(where:)
contains
λ μ£Όμ΄μ§ 쑰건μ λν΄Bool
μ체λ₯Ό λ°ννλ€.
μ΄κ²μCollection
μ λͺ¨λelements
λ₯Ό Logical OR Operator(||
) λ‘ μ°κ²°ν κ²κ³Ό κ°λ€.
(condition == element1) || (condition == element2) ||(condition == element3) || β¦
λ°λΌμ νλλΌλtrue
κ° λλ©΄ λ°λ‘ μ’ λ£ νtrue
λ₯Ό λ°ννκ³ , λ§μ§λ§κΉμ§false
μΌ κ²½μ°false
λ₯Ό λ°ννλ€.
filter
λ μ£Όμ΄μ§ 쑰건μ λν΄ true μΈelements
λ₯Όnew Collection
μΌλ‘ λ°ννλ€.
1 ) contains(_:)
contains(_:)
λ λ³λμ 쑰건μ κ°λ κ²μ λΆκ°λ₯νκ³ Switch μ κ°μ΄ Equal to(==)
λ₯Ό κΈ°μ€μΌλ‘ μ£Όμ΄μ§ 쑰건과
μΌμΉνλμ§ μ¬λΆλ§ νμΈνλ€.
μλ λ°°μ΄μ΄ train
μ ν¬ν¨νκ³ μλμ§ νμΈν΄λ³΄μ.
let words: [String] = ["room", "home", "train", "green", "heroe"]
- For-In Loops
let isIncluded: Bool = {
var isIncluded = false
for word in words {
if word == "train" {
isIncluded = true
break
}
}
return isIncluded
}()
print(isIncluded) // true
- OR Operator(
||
)
let isIncluded: Bool = words[0] == "train" ||
words[1] == "train" ||
words[2] == "train" ||
words[3] == "train" ||
words[4] == "train"
print(isIncluded) // true
- Switch
let isIncluded: Bool = {
switch true {
case words[0] == "train": return true
case words[1] == "train": return true
case words[2] == "train": return true
case words[3] == "train": return true
case words[4] == "train": return true
default: return false
}
}()
print(isIncluded) // true
let isIncluded: Bool = {
switch "train" {
case words[0], words[1], words[2], words[3], words[4]: return true
default: return false
}
}()
print(isIncluded) // true
- contains
μμμ For-In Loops λ₯Ό μ μΈν λ€λ₯Έ λ°©λ²λ€μ μ½λμ μ±λ₯κ³Ό μ μ°μ±μ΄ λ¨μ΄μ§λ€. κ·Έλλ§ κ°μ₯ μ’μ λ°©λ²μΈ For-In Loops μμ
μ½λκ° κΈΈκ³ κ°λ
μ±μ΄ μ’μ§ λͺ»νλ€.
κ·Έλ λ€λ©΄ contains λ μ΄λ₯Ό μΌλ§λ κ°λ¨νκ² κ΅¬νν μ μμκΉ?
let isIncluded: Bool = words.contains("train")
print(isIncluded) // true
μ λ§ μ΄κ² μ λΆλ€!!
λ§μ½ μ΄κ²μ κ΅³μ΄ filter λ‘ κ΅¬ννλ€λ©΄ μ΄λ»κ² ν΄μΌν κΉ?
let isIncluded: Bool = words.filter { $0 == "train" }.count > 0 ? true : false
print(isIncluded) // true
μ½λ κ°λ μ±λ μ© μ’μ§ λͺ»ν λΏ μλλΌ Collection μ λͺ¨λ elements λ₯Ό λ€ λμμ new Collection μ μμ±ν ν ν¬κΈ°λ₯Ό νλ¨ν΄μΌνλ―λ‘ μ±λ₯ λν λ¨μ΄μ§λ€.
2 ) contains(where:)
contains(_:)
κ° Switch μ κ°μ΄ Equal to(==)
λ₯Ό λΉκ΅νλ κ²κ³Ό λ¬λ¦¬ contains(where:)
λ if-statements
μ κ°μ΄
Bool
μ νλ¨ν 쑰건μ μ μν μ μλ€.
μ΄λ²μλ μ λ°°μ΄μ΄ elements
μ€ λ¬Έμ e
λ₯Ό ν¬ν¨νλ©΄μ, κΈΈμ΄κ° 5 μ΄μ
μΈ λ¬Έμλ₯Ό ν¬ν¨νκ³ μλμ§ νμΈν΄λ³΄μ.
let isIncluded: Bool = words.contains { $0.contains("e") && $0.count >= 5 }
print(isIncluded) // true
words λ°λ‘ λ€μ μ€λ contains λ contains(where:)
μ΄κ³ , closure λ΄λΆμ μλ contains λ contains(_:)
λ€.
contains
λ Bool`μ λν νλ¨λ§ νλ€. λ§μ½, λ¨μ§ ν¬ν¨λμ΄ μλμ§ μ¬λΆλ§ νμΈνλ κ²μ΄ μλλΌ κ·Έ element κ° λ¬΄μμΈμ§λ₯Ό μκ³ μΆλ€λ©΄ μ΄λ»κ² ν΄μΌν κΉ?
μ°λ¦¬λ filter μ contains λ₯Ό μνΈ λ³΄μμ μΌλ‘ ν¨κ» μ¬μ©ν¨μΌλ‘μ¨ μ΄λ₯Ό λ©μ§κ² μ²λ¦¬ν μ μλ€.
let wordsWithO = words.filter { $0.contains("o") }
print(wordsWithO) // ["room", "home", "heroe"]
let wordsWithO = words.filter { $0.contains("o") && $0.count >= 5 }
print(wordsWithO) // ["heroe"]
3 ) With Dictionaries
let temperatures = ["London": 7, "Athens": 14, "New York": 15, "Cairo": 19, "Sydney": 28]
let hasHighTemperatures = temperatures.contains { $0.value > 25 }
print(hasHighTemperatures) // true
4 ) With Classes or Structures
class Staff {
enum Gender {
case male, female
}
var name: String
var gender: Gender
var age: Int
init(name: String, gender: Gender, age: Int) {
self.name = name
self.gender = gender
self.age = age
}
}
struct Staff {
enum Gender {
case male, female
}
var name: String
var gender: Gender
var age: Int
}
let staff = [Staff(name: "Nick", gender: .male, age: 37),
Staff(name: "Julia", gender: .female, age: 29),
Staff(name: "Tom", gender: .male, age: 41),
Staff(name: "Tony", gender: .male, age: 45),
Staff(name: "Emily", gender: .female, age: 42),
Staff(name: "Irene", gender: .female, age: 30)]
let hasStaffOver40 = staff.contains { $0.age > 40 }
print("hasStaffOver40", hasSaffOver40)
let hasMalesOver50 = staff.contains { $0.age > 50 && $0.gender == .male }
print("hasMalesOver50", hasMalesOver50)
let hasFemalesUnder30 = staff.contains { $0.age < 30 && $0.gender == .female }
print("hasFemalesUnder30", hasFemalesUnder30)
8. allSatisfy
λ€μμ Swift documentation μ Instance Method allSatisfy(_:)
μ μ€λͺ
μ΄λ€.
func allSatisfy(_ predicate: (Self.Element) throws -> Bool) rethrows -> Bool
Link: Apple Developer Documentation
allSatisfy
μμcontains
μ λ§μ°¬κ°μ§λ‘ μ£Όμ΄μ§ 쑰건μ λν΄Bool
μ체λ₯Ό λ°ννλ€.
μ΄κ²μCollection
μ λͺ¨λelements
λ₯Ό Logical AND Operator(&&
) λ‘ μ°κ²°ν κ²κ³Ό κ°λ€.
(condition == element1) && (condition == element2) &&(condition == element3) || β¦
λ°λΌμ νλλΌλfalse
κ° λλ©΄ λ°λ‘ μ’ λ£ νfalse
λ₯Ό λ°ννκ³ , λ§μ§λ§κΉμ§true
μΌ κ²½μ°true
λ₯Ό λ°ννλ€.
μλ λ°°μ΄μ΄ λͺ¨λ κΈΈμ΄κ° 4 μ΄μ
μΈ λ¬Έμλ₯Ό ν¬ν¨νκ³ μλμ§ νμΈν΄λ³΄μ.
let words: [String] = ["room", "home", "train", "green", "heroe"]
- For-In Loops
let isAllTrue: Bool = {
var isAllTrue = true
for word in words {
if word.count < 4 {
isAllTrue = false
break
}
}
return isAllTrue
}()
print(isAllTrue) // true
- AND Operator(
&&
)
let isAllTrue: Bool = words[0].count >= 4 &&
words[1].count >= 4 &&
words[2].count >= 4 &&
words[3].count >= 4 &&
words[4].count >= 4
print(isAllTrue) // true
- Switch
let isAllTrue: Bool = {
switch true {
case words[0].count < 4: return false
case words[1].count < 4: return false
case words[2].count < 4: return false
case words[3].count < 4: return false
case words[4].count < 4: return false
default: return true
}
}()
print(isAllTrue) // true
- allSatisfy
μμμ For-In Loops λ₯Ό μ μΈν λ€λ₯Έ λ°©λ²λ€μ μ½λμ μ±λ₯κ³Ό μ μ°μ±μ΄ λ¨μ΄μ§λ€. κ·Έλλ§ κ°μ₯ μ’μ λ°©λ²μΈ For-In Loops μμ
μ½λκ° κΈΈκ³ κ°λ
μ±μ΄ μ’μ§ λͺ»νλ€.
κ·Έλ λ€λ©΄ allSatisfy λ μ΄λ₯Ό μΌλ§λ κ°λ¨νκ² κ΅¬νν μ μμκΉ?
let isAllTrue: Bool = words.allSatisfy { $0.count >= 4 }
print(isAllTrue) // true
μ λ§ μ΄κ² μ λΆλ€!!
λ§μ½ μ΄κ²μ κ΅³μ΄ filter λ‘ κ΅¬ννλ€λ©΄ μ΄λ»κ² ν΄μΌν κΉ?
let isAllTrue: Bool = words.filter { $0.count < 4 }.count > 0 ? false : true
print(isAllTrue) // true
μ½λ κ°λ μ±λ μ© μ’μ§ λͺ»ν λΏ μλλΌ Collection μ λͺ¨λ elements λ₯Ό λ€ λμμ new Collection μ μμ±ν ν ν¬κΈ°λ₯Ό νλ¨ν΄μΌνλ―λ‘ μ±λ₯ λν λ¨μ΄μ§λ€.
9. removeAll
λ€μμ Swift documentation μ Instance Method removeAll(_:)
μ μ€λͺ
μ΄λ€.
mutating func removeAll(where shouldBeRemoved: (Self.Element) throws -> Bool) rethrows
Link: Apple Developer Documentation
ν¨μμλ₯Ό 보면 mutating
μ΄ λΆμ΄μλ€. μ¦, remoeveAll(_:)
λ©μλλ new Collection μ λ°ννλ κ²μ΄ μλλΌ
original Collectionμ μμ
νλ€.
1 ) Compare with filter
κ°μ₯ κ°λ¨ν ννλ₯Ό ν΅ν΄ filter μ removeAll μ μ°¨μ΄λ₯Ό μμλ³Έλ€.
- filter
let scores: [Int] = [100, 75, 80, 66, 93, 52, 96, 87, 72]
let graterThanOrEqualNinety: [Int] = scores.filter { $0 >= 90 }
print(graterThanOrEqualNinety) // [100, 93, 96]
- removeAll
scores.removeAll { $0 >= 90 } // Cannot use mutating member on immutable value: 'scores' is a 'let' constant
print(scores)
removeAll μ΄ mutating
μ΄κΈ° λλ¬Έμ λ°°μ΄μ var
λ‘ μ μΈν΄μΌνλ€.
var scores: [Int] = [100, 75, 80, 66, 93, 52, 96, 87, 72]
scores.removeAll { $0 >= 90 }
print(scores) // [75, 80, 66, 52, 87, 72]
μ filter μ λμΌν κ²°κ³Όλ₯Ό λ§λ€λ €λ©΄ 쑰건μμ !
μ μ·¨ν΄ Bool
κ²°κ³Όλ₯Ό λ€μ§μ΄μ£Όλ©΄ λλ€.
scores.removeAll { $0 < 90 }
print(scores) // [100, 93, 96]
let graterThanOrEqualNinety = scores.removeAll { $0 < 90 }
print(graterThanOrEqualNinety) // ()
Closure μ 쑰건μμ΄ λμΌνλ€λ©΄ removeAll μ filter μ λ°λμ κ²°κ³Όλ₯Ό κ°λλ€. λν original Collection μ κ·Έλλ‘ λκ³
new Collection μ λ°ν
νλ filter μ λ¬λ¦¬ removeAll μoriginal Collection μ λ³κ²½
νλ€.removeAll μ Return Type μ
Void
λΌλ νμ μ νΉμν κ°μ λ°ννλ€. μ΄ κ°μ()
λ‘ μ°μ¬μ§Empty Tuple
μ΄λ€.
2 ) Compare with filter(_:)
& contains(_:)
var words: [String] = ["room", "home", "train", "green", "heroe"]
- filter
let wordsWithO: [String] = words.filter { $0.contains("o") }
print(wordsWithO) // ["room", "home", "heroe"]
- removeAll
words.removeAll { $0.contains("o") }
print(words) // ["train", "green"]
3 ) Compare with filter(_:)
& contains(where:)
var words: [String] = ["room", "home", "train", "green", "heroe"]
- filter
let wordsWithO = words.filter { $0.contains("o") && $0.count >= 5 }
print(wordsWithO) // ["heroe"]
- removeAll
words.removeAll { $0.contains("o") && $0.count >= 5 }
print(words) // ["room", "home", "train", "green"]
19. sort, sorted
λ€μμ Swift documentation μ Instance Method sort(by:)
μ sorted(by:)
μ μ€λͺ
μ΄λ€.
mutating func sort(by areInIncreasingOrder: (Self.Element, Self.Element) throws -> Bool) rethrows
func sorted(by areInIncreasingOrder: (Self.Element, Self.Element) throws -> Bool) rethrows -> [Self.Element]
Link: Apple Developer Documentation sort(by:)
Link: Apple Developer Documentation sorted(by:)
Swift μ Higher-order Functions μ μ λ ¬μλ 2κ°μ§κ° μλ€.
- sort: Closure μ 쑰건μ λ°λΌ
original Collection μ μ λ ¬
νλ€. - sorted: Closure μ 쑰건μ λ°λΌ μ λ ¬ ν
new Collection μ λ°ν
νλ€.
1 ) Ascending Order
μλ λ°°μ΄μ μ€λ¦μ°¨μμΌλ‘ μ λ ¬ν΄λ³΄μ.
var numbers: [Int] = [5, 87, 2, 6, 15, 24, 8, 42, 74, 9, 32]
- For-In Loops
var swap: Bool = false
repeat {
swap = false
for i in 0..<numbers.count - 1 {
if numbers[i] > numbers[i + 1] {
let temp = numbers[i + 1]
numbers[i + 1] = numbers[i]
numbers[i] = temp
swap = true
}
}
} while swap
print(numbers) // [2, 5, 6, 8, 9, 15, 24, 32, 42, 74, 87]
- sort
sort λ₯Ό μ΄μ©νλ©΄ λ€μκ³Ό κ°μ΄ μ½κ² μ λ ¬μ΄ κ°λ₯νλ€.
var numbers: [Int] = [5, 87, 2, 6, 15, 24, 8, 42, 74, 9, 32]
numbers.sort { $0 < $1 }
λλΆλΆμ κ²½μ°λ Trailing Closures λ₯Ό μ¬μ©νλ κ²μ΄ λ κΉλν μ½λλ₯Ό μ 곡νμ§λ§ μ λ ¬ ν¨μλ Shorthand Argument Names λ§μ λ μλ΅ κ°λ₯νκΈ° λλ¬Έμ λ€μκ³Ό κ°μ΄ μμ±νλ©΄ μ½λλ₯Ό λ μ€μΌ μ μλ€.
numbers.sort(by: <)
λ§μ§λ§μΌλ‘ sort(by:)
μ κΈ°λ³Έ λμμ Ascending Order
μ΄κΈ° λλ¬Έμ μ΄ λ§μ λ μλ΅ κ°λ₯νλ€.
numbers.sort()
print(numbers) // [2, 5, 6, 8, 9, 15, 24, 32, 42, 74, 87]
- sorted
λλ‘λ μλ³Έ λ°°μ΄μ μμ νμ§ μκ³ μ λ ¬λ μ λ°°μ΄μ΄ νμν μ μλ€. sort(by:)
λ mutating
μ΄κΈ° λλ¬Έμ μ΄λ₯Ό μν΄μ
sort(by:)
λ₯Ό νκΈ° μ λ°°μ΄μ 미리 볡μ¬ν΄μΌνλ€. λλ μλ³Έ λ°°μ΄μ΄ let
μΌλ‘ μ μΈλμ΄ λ³κ²½ν μ μμ μλ μλ€.
μ΄λ μ¬μ©νλ©΄ μ’μ ν¨μκ° sorted(by:)
λ€.
var numbers: [Int] = [5, 87, 2, 6, 15, 24, 8, 42, 74, 9, 32]
let ascendingOrdered = numbers.sorted { $0 < $1 }
print(ascendingOrdered) // [2, 5, 6, 8, 9, 15, 24, 32, 42, 74, 87]
print(numbers) // [5, 87, 2, 6, 15, 24, 8, 42, 74, 9, 32]
sorted(by:)
μμ Trailing Closures λ₯Ό μ¬μ©νμ§ μλ κ²μ΄ λ κΉλν μ½λ μμ±μ΄ κ°λ₯νλ€.
let ascendingOrdered = numbers.sorted(by: <)
λ§μ°¬κ°μ§λ‘ by: <
λ§μ λ μλ΅ κ°λ₯νλ€.
let ascendingOrdered = numbers.sorted()
print(ascendingOrdered) // [2, 5, 6, 8, 9, 15, 24, 32, 42, 74, 87]
2 ) Descending Order
- sort
var numbers: [Int] = [5, 87, 2, 6, 15, 24, 8, 42, 74, 9, 32]
numbers.sort(by: >)
print(numbers) // [87, 74, 42, 32, 24, 15, 9, 8, 6, 5, 2]
- sorted
var numbers: [Int] = [5, 87, 2, 6, 15, 24, 8, 42, 74, 9, 32]
let descendingOrdered = numbers.sorted(by: >)
print(descendingOrdered) // [87, 74, 42, 32, 24, 15, 9, 8, 6, 5, 2]
11. split
λ€μμ Swift documentation μ Instance Method compactMap(_:)
μ μ€λͺ
μ΄λ€.
func split(
separator: Self.Element,
maxSplits: Int = Int.max,
omittingEmptySubsequences: Bool = true
) -> [Self.SubSequence]
func split(
maxSplits: Int = Int.max,
omittingEmptySubsequences: Bool = true,
whereSeparator isSeparator: (Self.Element) throws -> Bool
) rethrows -> [Self.SubSequence]
Link: Apple Developer Documentation
Link: Apple Developer Documentation
split μ μ£Όμ΄μ§ 쑰건μ λ°λΌ λλ
μκΈ° μμ μ SubSequence νμ
μnew Collection
μ λ°ννλ€.μλ₯Ό λ€μ΄
String
μ split νλ©΄String.SubSequence
μΈSubstring
νμ μnew Collection
μ¦,Array<Substring>
(=[Substring]
)μ λ°ννλ€.
Substring μ λ€μ λ§ν¬λ₯Ό μ°Έκ³ νλ€. About Substrings
- split(separator:maxSplits:omittingEmptySubsequences:)
let line = "BLANCHE: I don't want realism. I want magic!"
split μ μν΄ " "
λ₯Ό κΈ°μ€μΌλ‘ λλμ΄ μκΈ΄ Substring
μ΄ Collection Array
μ λ΄κ²Όλ€.
print(type(of: line)) // String
let splited = line.split(separator: " ")
print(splited) // ["BLANCHE:", "I", "don\'t", "want", "realism.", "I", "want", "magic!"]
print(type(of: splited)) // Array<Substring>
maxSplits
λ₯Ό ν΅ν΄ λͺ λ² split μ ν κ²μΈμ§ μ ν μ μλ€.
let splitedMaxOne = line.split(separator: " ", maxSplits: 1)
print(splitedMaxOne) // ["BLANCHE:", " I don\'t want realism. I want magic!"]
split μ κΈ°λ³Έμ μΌλ‘ White-Space
λ₯Ό 무μνλ€. λ°λΌμ μ΄λ₯Ό 무μνμ§ μμΌλ €λ©΄ omittingEmptySubsequences
μ
argument λ‘ false
λ₯Ό μ λ¬νλ€.
print(line.split(separator: " ", omittingEmptySubsequences: true)) // default
// ["BLANCHE:", "I", "don\'t", "want", "realism.", "I", "want", "magic!"]
print(line.split(separator: " ", omittingEmptySubsequences: false))
// ["BLANCHE:", "", "", "I", "don\'t", "want", "realism.", "I", "want", "magic!"]
- split(maxSplits:omittingEmptySubsequences:whereSeparator:)
μ split κ³Ό λμΌν μν μ νλ split μ΄λ€. λ€λ§, μ split μ λλλ κΈ°μ€μ μ§μ νλ separator
κ°
첫 λ²μ§Έ argument μμΌλ μ΄ split ν¨μλ λ§μ§λ§ whereSeparator
κ° λ§μ§λ§ argumentλ‘ μ¨λ€.
μ¦, separator
λ₯Ό Trailing Closure λ‘ μμ±νκΈ° μν΄ μ 곡λλ λ€λ₯Έ ννμ λμΌν split
ν¨μλ€.
let line = "BLANCHE: I don't want realism. I want magic!"
let splited = line.split { $0 == " " }
print(splited) // ["BLANCHE:", "I", "don\'t", "want", "realism.", "I", "want", "magic!"]
print(type(of: splited)) // Array<Substring>
Reference
- βFirst-class citizen.β Wikipedia. Oct. 15, 2022, Wikipedia - First Class Citizen.
- βFirst-class function.β Wikipedia. Jul. 14, 2022, Wikipedia - First Class Function.
- βHigher-order function.β Wikipedia. Sep. 8, 2022, Wikipedia - Higher-Order Function.
- βNon-local variable.β Wikipedia. May. 12, 2022, Wikipedia - Non-local Variable.
- βHigher-Order Functions in Swift.β Medium, Jun. 9, 2020, Higher-Order Functions in Swift.
- βUnderstanding Higher Order Functions in Swift.β APPCODA, Feb. 26, 2020, Understanding Higher Order Functions in Swift.
- βHigher Order Functions in Swift.β Level Up Coding, Aug. 12, 2020, Level Up Coding - Higher Order Functions in Swift.