Skip to content

Commit e64cff7

Browse files
Qataxwu
andauthored
Add Sequence.firstNonNil(_:) (#31)
* Add Sequence.firstNonNil(of:) and associated tests * Rename First.swift to FirstTests.swift * Address PR comments by adding guide and changing naming * Address PR comments by changing name * Update Guides/FirstNonNil.md Co-authored-by: Xiaodi Wu <[email protected]> * Update Sources/Algorithms/FirstNonNil.swift Co-authored-by: Xiaodi Wu <[email protected]> Co-authored-by: Xiaodi Wu <[email protected]>
1 parent 98b6e26 commit e64cff7

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

Guides/FirstNonNil.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# First Non-Nil
2+
3+
[[Source](https://github.com/apple/swift-algorithms/blob/main/Sources/Algorithms/FirstNonNil.swift) |
4+
[Tests](https://github.com/apple/swift-algorithms/blob/main/Tests/SwiftAlgorithmsTests/FirstNonNilTests.swift)]
5+
6+
Retrieves the first `.some` encountered while applying the given transform.
7+
8+
This operation is available through the `firstNonNil(_:)` method on any sequence.
9+
10+
```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
16+
```
17+
18+
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.
22+
23+
## Detailed Design
24+
25+
The `firstNonNil(_:)` method is added as an extension method on the `Sequence`
26+
protocol:
27+
28+
```swift
29+
public extension Sequence {
30+
func firstNonNil<Result>(_ transform: (Element) throws -> Result?)
31+
rethrows -> Result?
32+
}
33+
34+
```
35+
36+
### Naming
37+
38+
This method’s name was selected for its comprehensibility.
39+
40+
### Comparison with other languages
41+
42+
**Scala**: Scala provides a `collectFirst` function that finds the first element
43+
in a collection for which a partial function is defined.

Sources/Algorithms/FirstNonNil.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Algorithms open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
//===----------------------------------------------------------------------===//
13+
// firstNonNil(_:)
14+
//===----------------------------------------------------------------------===//
15+
16+
public extension Sequence {
17+
/// Returns the first element in `self` that `transform` maps to a `.some`.
18+
func firstNonNil<Result>(
19+
_ transform: (Element) throws -> Result?
20+
) rethrows -> Result? {
21+
for value in self {
22+
if let value = try transform(value) {
23+
return value
24+
}
25+
}
26+
return nil
27+
}
28+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Algorithms open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
import XCTest
13+
import Algorithms
14+
15+
final class FirstNonNilTests: XCTestCase {
16+
func testFirstNonNil() {
17+
XCTAssertNil([].firstNonNil { $0 })
18+
XCTAssertNil(["A", "B", "C"].firstNonNil { Int($0) })
19+
XCTAssertNil(["A", "B", "C"].firstNonNil { _ in nil })
20+
XCTAssertEqual(["A", "B", "10"].firstNonNil { Int($0) }, 10)
21+
XCTAssertEqual(["20", "B", "10"].firstNonNil { Int($0) }, 20)
22+
}
23+
}

0 commit comments

Comments
 (0)