22
33[[ Source] ( https://github.com/apple/swift-algorithms/blob/main/Sources/Algorithms/FirstNonNil.swift ) |
44 [ Tests] ( https://github.com/apple/swift-algorithms/blob/main/Tests/SwiftAlgorithmsTests/FirstNonNilTests.swift )]
5+
6+ Returns the first non-` nil ` result obtained from applying the given
7+ transformation to the elements of the sequence.
58
6- Retrieves the first ` .some ` encountered while applying the given transform.
9+ ``` swift
10+ let strings = [" three" , " 3.14" , " -5" , " 2" ]
11+ if let firstInt = strings.firstNonNil ({ Int ($0 ) }) {
12+ print (firstInt)
13+ // -5
14+ }
15+ ```
716
8- This operation is available through the ` firstNonNil(_:) ` method on any sequence.
17+ Like ` first(where:) ` , this method stops iterating the sequence once a match is
18+ found. Use ` firstNonNil(_:) ` to avoid having to apply a transformation twice:
919
1020``` swift
11- let value = [" A" , " B" , " 10" ].firstNonNil { Int ($0 ) }
12- // value == .some(10)
13- //
14- let noValue = [" A" , " B" , " C" ].firstNonNil { Int ($0 ) }
15- // noValue == .none
21+ let strings = [" three" , " 3.14" , " -5" , " 2" ]
22+ if let firstIntAsString = strings.first (where : { Int ($0 ) != nil }) {
23+ let firstInt = Int (firstIntAsString)! // :(
24+ // ...
25+ }
26+ ```
27+
28+ This method's behavior can also be approximated using ` compactMap(_:) ` :
29+
30+ ``` swift
31+ let strings = [" three" , " 3.14" , " -5" , " 2" ]
32+ if let firstInt = strings.compactMap ({ Int ($0 ) }).first {
33+ // ...
34+ }
1635```
1736
37+ However, unlike ` firstNonNil(_:) ` and ` first(where:) ` , ` compactMap(_:) ` does not
38+ stop iterating the sequence once the first match is found. Adding ` .lazy ` fixes
39+ this, at the cost of requiring an escaping closure that you cannot ` throw ` from:
1840
19- This method is analogous to ` first(where:) ` in how it only consumes values until
20- a ` .some ` is found, unlike using lazy operators, which will load any sequence into a collection
21- before evaluating its transforms lazily.
41+ ``` swift
42+ let strings = [" three" , " 3.14" , " -5" , " 2" ]
43+ if let firstInt = strings.lazy .compactMap ({ Int ($0 ) }).first {
44+ // ...
45+ }
46+ ```
2247
2348## Detailed Design
2449
@@ -27,17 +52,34 @@ protocol:
2752
2853``` swift
2954public extension Sequence {
30- func firstNonNil <Result >(_ transform : (Element ) throws -> Result? )
31- rethrows -> Result?
55+ func firstNonNil <Result >(
56+ _ transform : (Element ) throws -> Result?
57+ ) rethrows -> Result?
3258}
33-
3459```
3560
61+ ### Complexity
62+
63+ ` firstNonNil(_:) ` is an O(* n* ) operation, where * n* is the number of
64+ elements at the start of the sequence that result in ` nil ` when applying the
65+ transformation.
66+
3667### Naming
3768
38- This method’s name was selected for its comprehensibility.
69+ Some alternative names were considered:
70+
71+ * ` compactMapFirst(_:) `
72+ * ` first(mapping:) `
73+ * ` firstSome(_:) `
74+ * ` firstMap(_:) `
3975
4076### Comparison with other languages
4177
42- ** Scala** : Scala provides a ` collectFirst ` function that finds the first element
43- in a collection for which a partial function is defined.
78+ ** Haskell** : Haskell includes the ` firstJust ` method, which has the same
79+ semantics as the ` firstNonNil(_:) ` method.
80+
81+ ** Rust** : Rust includes the ` find_map ` method, which has the same semantics as
82+ the ` firstNonNil(_:) ` method.
83+
84+ ** Scala** : Scala includes the ` collectFirst ` method, which has the same
85+ semantics as the ` firstNonNil(_:) ` method.
0 commit comments