Reputation: 1757
I expect allMembers
to be of type [Member]
. But instead its type is [[Member]]
. Why compactMap
does not return result of [Member]
type?
class Team {
let members = Array(repeating: Member(), count: 2)
}
class Member {
}
let teams = Array(repeating: Team(), count: 3)
let allMembers = teams.compactMap { $0.members }
Upvotes: 2
Views: 1796
Reputation: 5669
Adding some detail in @David's answer:
Using flatMap on a sequence (like an Array) filtering anything that maps to nil is now deprecated and replaced by compactMap.
Using flatMap on a sequence with a closure that returns an optional.
Sequence.flatMap<U>(_ transform: (Element) -> U?) -> U?
For example:
Rather than:
let names: [String?] = ["Tom", nil, "Peter", nil, "Harry"]
let valid = names.flatMap { $0 }
You have to use:
let valid = names.compactMap { $0 }
// ["Tom", "Peter", "Harry"]
let names: [String?] = ["Tom", nil, "Peter", nil, "Harry"]
let counts = names.compactMap { $0?.count }
// [3, 5, 5]
But again, Swift 4.1 does not deprecate all uses of flatMap - out of 3 cases, only one case is changing. Below two situations are as it is where you need to use flatMap:
1) Using flatMap on a sequence with a closure that returns a sequence:
Sequence.flatMap<S>(_ transform: (Element) -> S) -> [S.Element] where S : Sequence
Example:
let scores = [[5,2,7], [4,8], [9,1,3]]
let allScores = scores.flatMap { $0 }
// [5, 2, 7, 4, 8, 9, 1, 3]
let passMarks = scores.flatMap { $0.filter { $0 > 5} }
// [7, 8, 9]
2) Using flatMap on an optional: The closure takes the non-nil value of the optional and returns an optional. If the original optional is nil then flatMap returns nil:
Optional.flatMap<U>(_ transform: (Wrapped) -> U?) -> U?
Example:
let input: Int? = Int("8")
let passMark: Int? = input.flatMap { $0 > 5 ? $0 : nil}
// Optional(8)
For more detail, please refer here
Upvotes: 0
Reputation: 54706
You actually need flatMap
, not compactMap
.
Even though previously (before Swift 4.1), compactMap
was also called flatMap
, it had a different implementation and function signature than the current flatMap
, since compactMap
can be used instead of consecutive map
and filter
calls to map
each element to a new element while only keeping non-nil
elements. On the other hand, flatMap
flattens out nested lists while mapping elements.
This is the still existing flatMap
on Sequence
, while this is the deprecated flatMap
on Sequence
that was renamed to compactMap
. As you can see, the function signature of the renamed version was
func flatMap<ElementOfResult>(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
, so its closure input argument returned an Optional
value (just like compactMap
does now), while the still existing flatMap
has a function signature
func flatMap<SegmentOfResult>(_ transform: (Self.Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
, which doesn't return an Optional
in its closure.
You should use the non-deprecated flatMap
to flatten out your nested Array<Array<Member>>
.
let allMembers = teams.flatMap { $0.members }
Upvotes: 3