There is map
as a typical operation for collections and so-called" guys with values in something ".
However, there are variants of map
, which can be confusing, so I'd like to organize them.
In this article, an array is used as an example. In fact, arrays, dictionaries, and optional "containers" provide similar operations (though not exactly the same).
map Transforms each element in the array. Since all elements are converted, the number of elements does not change before and after conversion.
compactMap
Same as map
, but excludes nil
from the elements and unwraps Optional. Since nil
is excluded, the number of elements may change (decrease) before and after conversion unlike map
.
flatMap If the array is nested, extract the elements from the inner array into a flat array (2D array-> 1D array).
If you think of the inner "** container ** called array" as "** container ** called Optional", you will create an "array with the contents of Optional extracted", which is the same operation as compactMap
.
--Array <Array <element >>
-(conversion)-> Array <element>
--Array <Optional <element >>
-(conversion)-> Array <element>
Early versions of Swift, which did not implement compactMap
, were also used for this purpose, but are now deprecated. Let's use compactMap
obediently.
This is a sample using map
, compactMap
, flatMap
.
Please read it while comparing it with the above four figures.
import Foundation
enum Category: String, CustomStringConvertible {
var description: String {
self.rawValue
}
case personal
case business
}
struct Item: CustomStringConvertible {
var description: String {
"""
name: "\(self.name)", price: \(self.price), categories: \(self.categories ?? [])
"""
}
let name: String
let price: Int
let categories: [Category]?
}
let items: [Item] = [
Item(name: "Suit", price: 15000, categories: [.business]),
Item(name: "Pen", price: 400, categories: [.personal, .business]),
Item(name: "Sea", price: 99999, categories: nil),
Item(name: "Drink", price: 120, categories: [.personal]),
Item(name: "Sky", price: 99999, categories:nil),
Item(name: "Comic", price: 600, categories: [.personal])
]
print("""
== Items ==========
\(items)
"""
)
// map transforms each element in an Array.
let map = items.map { item in
item.categories ?? []
}
print("""
== map "item.categories ?? []" ==========
\(map)
"""
)
// compactMap is a map that only collect non-nil values.
let compact = items.compactMap { item in
item.categories
}
print("""
== compactMap "item.categories" ==========
\(compact)
"""
)
// flatMap flattens the inner Array.
let flat1 = items.flatMap { item in
item.categories ?? []
}
print("""
== flatMap "item.categories ?? []" ==========
\(flat1)
"""
)
// This type of flatMap is deprecated. You should use compactMap.
let flat2 = items.flatMap { item in
item.categories
}
print("""
== flatMap "item.categories" ==========
\(flat2)
"""
)
== Items ==========
[name: "Suit", price: 15000, categories: [business]
, name: "Pen", price: 400, categories: [personal, business]
, name: "Sea", price: 99999, categories: []
, name: "Drink", price: 120, categories: [personal]
, name: "Sky", price: 99999, categories: []
, name: "Comic", price: 600, categories: [personal]
]
== map "item.categories ?? []" ==========
[[business], [personal, business], [], [personal], [], [personal]]
== compactMap "item.categories" ==========
[[business], [personal, business], [personal], [personal]]
== flatMap "item.categories ?? []" ==========
[business, personal, business, personal, personal]
== flatMap "item.categories" ==========
[[business], [personal, business], [personal], [personal]]
It's easy to understand map
if you show it in a diagram. Operations around here are often used in the Combine framework, so I think it will be very easy to develop if you can master it.