Skip to content

Commit 78dfa23

Browse files
authored
Add async map and filter to array (#10)
1 parent 6fe18c3 commit 78dfa23

File tree

3 files changed

+49
-26
lines changed

3 files changed

+49
-26
lines changed

Sources/Fork/Extensions/Array+ForkedArray.swift

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,39 @@ extension Array {
22
/// Create a ``ForkedArray`` from the current `Array`
33
public func fork<Output>(
44
filter: @escaping (Element) async throws -> Bool = { _ in true },
5-
output: @escaping (Element) async throws -> Output
5+
map: @escaping (Element) async throws -> Output
66
) -> ForkedArray<Element, Output> {
77
ForkedArray(
88
self,
99
filter: filter,
10-
output: output
10+
map: map
1111
)
1212
}
13+
14+
/// Create a ``ForkedArray`` from the current `Array` and get the Output Array
15+
public func forked<Output>(
16+
filter: @escaping (Element) async throws -> Bool,
17+
map: @escaping (Element) async throws -> Output
18+
) async throws -> [Output] {
19+
try await ForkedArray(
20+
self,
21+
filter: filter,
22+
map: map
23+
)
24+
.output()
25+
}
26+
27+
/// Returns an array containing the results of mapping the given closure over the sequence’s elements.
28+
public func asyncMap<Output>(
29+
_ transform: @escaping (Element) async throws -> Output
30+
) async throws -> [Output] {
31+
try await fork(map: transform).output()
32+
}
33+
34+
/// Returns an array containing only the true results from the given closure over the sequence’s elements.
35+
public func asyncFilter(
36+
_ isIncluded: @escaping (Element) async throws -> Bool
37+
) async throws -> [Element] {
38+
try await fork(filter: isIncluded, map: identity).output()
39+
}
1340
}

Sources/Fork/ForkedArray.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public struct ForkedArray<Value, Output> {
77
}
88

99
private let filter: (Value) async throws -> Bool
10-
private let output: (Value) async throws -> Output
10+
private let map: (Value) async throws -> Output
1111
private let fork: Fork<ForkType, ForkType>
1212

1313
/// The input array used to get the output
@@ -21,11 +21,11 @@ public struct ForkedArray<Value, Output> {
2121
public init(
2222
_ array: [Value],
2323
filter: @escaping (Value) async throws -> Bool = { _ in true },
24-
output: @escaping (Value) async throws -> Output
24+
map: @escaping (Value) async throws -> Output
2525
) {
2626
self.array = array
2727
self.filter = filter
28-
self.output = output
28+
self.map = map
2929

3030
switch ForkedArray.split(array: array) {
3131
case .none:
@@ -49,8 +49,8 @@ public struct ForkedArray<Value, Output> {
4949
public func output() async throws -> [Output] {
5050
try await fork.merged(
5151
using: { leftForkType, rightForkType in
52-
async let leftOutput = try await ForkedArray.output(for: leftForkType, filter: filter, using: output)
53-
async let rightOutput = try await ForkedArray.output(for: rightForkType, filter: filter, using: output)
52+
async let leftOutput = try await ForkedArray.output(for: leftForkType, isIncluded: filter, transform: map)
53+
async let rightOutput = try await ForkedArray.output(for: rightForkType, isIncluded: filter, transform: map)
5454

5555
return try await leftOutput + rightOutput
5656
}
@@ -95,23 +95,23 @@ extension ForkedArray {
9595

9696
private static func output(
9797
for type: ForkType,
98-
filter: @escaping (Value) async throws -> Bool,
99-
using: @escaping (Value) async throws -> Output
98+
isIncluded: @escaping (Value) async throws -> Bool,
99+
transform: @escaping (Value) async throws -> Output
100100
) async throws -> [Output] {
101101
switch type {
102102
case .none:
103103
return []
104104
case let .single(value):
105-
guard try await filter(value) else { return [] }
105+
guard try await isIncluded(value) else { return [] }
106106

107107
try Task.checkCancellation()
108108

109-
return [try await using(value)]
109+
return [try await transform(value)]
110110
case let .fork(fork):
111111
return try await fork.merged(
112112
using: { leftType, rightType in
113-
async let leftOutput = try output(for: leftType, filter: filter, using: using)
114-
async let rightOutput = try output(for: rightType, filter: filter, using: using)
113+
async let leftOutput = try output(for: leftType, isIncluded: isIncluded, transform: transform)
114+
async let rightOutput = try output(for: rightType, isIncluded: isIncluded, transform: transform)
115115

116116
try Task.checkCancellation()
117117

Tests/ForkTests/ForkedArrayTests.swift

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,51 +7,47 @@ class ForkedArrayTests: XCTestCase {
77
@Sendable func downloadPhoto(named: String) async -> String { named }
88
func show(_ photos: [String]) { }
99

10-
let forkedArray = ForkedArray(photoNames, output: downloadPhoto(named:))
10+
let forkedArray = ForkedArray(photoNames, map: downloadPhoto(named:))
1111
let photos = try await forkedArray.output()
1212

1313
XCTAssertEqual(photos, photoNames)
1414
}
1515

1616
func testForkedArray_one() async throws {
1717
let photoNames = ["one"]
18-
@Sendable func downloadPhoto(named: String) async -> String { named }
19-
func show(_ photos: [String]) { }
18+
@Sendable func isValidPhoto(named: String) async -> Bool { true }
2019

21-
let forkedArray = ForkedArray(photoNames, output: downloadPhoto(named:))
22-
let photos = try await forkedArray.output()
20+
let photos = try await photoNames.asyncFilter(isValidPhoto(named:))
2321

2422
XCTAssertEqual(photos, photoNames)
2523
}
2624

2725
func testForkedArray_two() async throws {
2826
let photoNames = ["one", "two"]
2927
@Sendable func downloadPhoto(named: String) async -> String { named }
30-
func show(_ photos: [String]) { }
3128

32-
let forkedArray = ForkedArray(photoNames, output: downloadPhoto(named:))
33-
let photos = try await forkedArray.output()
29+
let photos = try await photoNames.forked(
30+
filter: { _ in true },
31+
map: downloadPhoto(named:)
32+
)
3433

3534
XCTAssertEqual(photos, photoNames)
3635
}
3736

3837
func testForkedArray_three() async throws {
3938
let photoNames = ["one", "two", "three"]
4039
@Sendable func downloadPhoto(named: String) async -> String { named }
41-
func show(_ photos: [String]) { }
4240

43-
let forkedArray = ForkedArray(photoNames, output: downloadPhoto(named:))
44-
let photos = try await forkedArray.output()
41+
let photos = try await photoNames.asyncMap(downloadPhoto(named:))
4542

4643
XCTAssertEqual(photos, photoNames)
4744
}
4845

4946
func testForkedArray_x() async throws {
5047
let photoNames = (0 ... Int.random(in: 3 ..< 100)).map(\.description)
5148
@Sendable func downloadPhoto(named: String) async -> String { named }
52-
func show(_ photos: [String]) { }
5349

54-
let forkedArray = photoNames.fork(output: downloadPhoto(named:))
50+
let forkedArray = photoNames.fork(map: downloadPhoto(named:))
5551
let photos = try await forkedArray.output()
5652

5753
XCTAssertEqual(photos, photoNames)

0 commit comments

Comments
 (0)