'swift: Elegant Way to Map Optional to Array
I am looking for an elegant way to map an Optional to an Array. What I mean by that is the following:
- If the
Optionalis.none, return an emptyArray<Wrapped> - If the
Optionalis.some, return a single elementArray<Wrapped>
Now this can be done like this
let seq = value.map { [$0] } ?? []
Unfortunately this gets quite ugly and illegible when you want to use it inline.
Is there a better method to accomplish this, without writing a extension?
Solution 1:[1]
How about putting your optional in an array, and compactMap that array with the identity function?
[yourOptional].compactMap { $0 }
As Martin R suggested, you can use CollectionOfOne to save the creation of a throwaway array, at the cost of writing a few more characters:
CollectionOfOne(yourOptional).compactMap { $0 }
Solution 2:[2]
Is there a better method to accomplish this, without writing a extension?
No. The method you're looking for still hasn't made its way into the Swift Standard Library.
public extension Optional {
/// Create a single-element array literal, or an empty one.
/// - Returns: `[self!]` if `.some`; `[]` if `nil`.
/// - Note: This cannot be generalized to all types,
/// as Swift doesn't employ universal non-optional defaults.
func compacted<ExpressibleByArrayLiteral: Swift.ExpressibleByArrayLiteral>() -> ExpressibleByArrayLiteral
where ExpressibleByArrayLiteral.ArrayLiteralElement == Wrapped {
.init(compacting: self)
}
}
// MARK: - ExpressibleByArrayLiteral
public extension ExpressibleByArrayLiteral {
/// Create a single-element array literal, or an empty one.
/// - Returns: `[optional!]` if `.some`; `[]` if `nil`.
/// - Note: This cannot be generalized to all types,
/// as Swift doesn't employ universal non-optional defaults.
init(compacting optional: ArrayLiteralElement?) {
self = optional.map { [$0] } ?? []
}
}
XCTAssertEqual(
["??"],
("??" as Optional).compacted()
)
XCTAssertEqual(
Set(),
Int?.none.compacted()
)
C# is an example of a language with "universal non-optional defaults".
NSPointerArray has the argument-less compact, which is a similar concept, and the inspiration for the first half of the compactMap that does exist in the standard library. It's now available as compacted.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |
