Skip to content

Commit b56c15a

Browse files
committed
Merge pull request #2461 from russbishop/fork/master
2 parents 670f7b5 + 7dc71d0 commit b56c15a

File tree

3 files changed

+84
-4
lines changed

3 files changed

+84
-4
lines changed

stdlib/public/core/FlatMap.swift

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,25 @@ extension LazySequenceProtocol {
2424
FlattenSequence<LazyMapSequence<Elements, SegmentOfResult>>> {
2525
return self.map(transform).flatten()
2626
}
27+
28+
/// Returns a `LazyMapSequence` containing the concatenated non-nil
29+
/// results of mapping transform over this `Sequence`.
30+
///
31+
/// Use this method to receive only nonoptional values when your
32+
/// transformation produces an optional value.
33+
///
34+
/// - Parameter transform: A closure that accepts an element of this
35+
/// sequence as its argument and returns an optional value.
36+
@warn_unused_result
37+
public func flatMap<ElementOfResult>(
38+
_ transform: (Elements.Iterator.Element) -> ElementOfResult?
39+
) -> LazyMapSequence<
40+
LazyFilterSequence<
41+
LazyMapSequence<Elements, ElementOfResult?>>,
42+
ElementOfResult
43+
> {
44+
return self.map(transform).filter { $0 != nil }.map { $0! }
45+
}
2746
}
2847

2948
extension LazyCollectionProtocol {
@@ -42,6 +61,25 @@ extension LazyCollectionProtocol {
4261
> {
4362
return self.map(transform).flatten()
4463
}
64+
65+
/// Returns a `LazyMapCollection` containing the concatenated non-nil
66+
/// results of mapping transform over this collection.
67+
///
68+
/// Use this method to receive only nonoptional values when your
69+
/// transformation produces an optional value.
70+
///
71+
/// - Parameter transform: A closure that accepts an element of this
72+
/// collection as its argument and returns an optional value.
73+
@warn_unused_result
74+
public func flatMap<ElementOfResult>(
75+
_ transform: (Elements.Iterator.Element) -> ElementOfResult?
76+
) -> LazyMapCollection<
77+
LazyFilterCollection<
78+
LazyMapCollection<Elements, ElementOfResult?>>,
79+
ElementOfResult
80+
> {
81+
return self.map(transform).filter { $0 != nil }.map { $0! }
82+
}
4583
}
4684

4785
extension LazyCollectionProtocol
@@ -67,4 +105,22 @@ extension LazyCollectionProtocol
67105
>> {
68106
return self.map(transform).flatten()
69107
}
108+
109+
/// Returns a `LazyMapBidirectionalCollection` containing the concatenated non-nil
110+
/// results of mapping transform over this collection.
111+
///
112+
/// Use this method to receive only nonoptional values when your
113+
/// transformation produces an optional value.
114+
///
115+
/// - Parameter transform: A closure that accepts an element of this
116+
/// collection as its argument and returns an optional value.
117+
public func flatMap<ElementOfResult>(
118+
_ transform: (Elements.Iterator.Element) -> ElementOfResult?
119+
) -> LazyMapBidirectionalCollection<
120+
LazyFilterBidirectionalCollection<
121+
LazyMapBidirectionalCollection<Elements, ElementOfResult?>>,
122+
ElementOfResult
123+
> {
124+
return self.map(transform).filter { $0 != nil }.map { $0! }
125+
}
70126
}

stdlib/public/core/SequenceAlgorithms.swift.gyb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -657,10 +657,10 @@ extension Sequence {
657657
/// - Complexity: O(*m* + *n*), where *m* is the length of this sequence
658658
/// and *n* is the length of the result.
659659
@warn_unused_result
660-
public func flatMap<T>(
661-
_ transform: @noescape (${GElement}) throws -> T?
662-
) rethrows -> [T] {
663-
var result: [T] = []
660+
public func flatMap<ElementOfResult>(
661+
_ transform: @noescape (${GElement}) throws -> ElementOfResult?
662+
) rethrows -> [ElementOfResult] {
663+
var result: [ElementOfResult] = []
664664
for element in self {
665665
if let newElement = try transform(element) {
666666
result.append(newElement)

test/1_stdlib/Inputs/flatMap.gyb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,29 @@ ${Test}.test("flatMap/${Kind}/Lazy") {
6464
+ "once per element")
6565
% end
6666
}
67+
68+
for test in flatMapToOptionalTests {
69+
let s = ${Minimal}<OpaqueValue<Int>>(elements:
70+
test.sequence.map(OpaqueValue.init))
71+
let closureLifetimeTracker = LifetimeTracked(0)
72+
var timesClosureWasCalled = 0
73+
74+
var result = s.lazy.flatMap {
75+
(element: OpaqueValue<Int>) -> OpaqueValue<Int32>? in
76+
_blackHole(closureLifetimeTracker)
77+
timesClosureWasCalled += 1
78+
return test.transform(element.value).map(OpaqueValue.init)
79+
}
80+
expectEqual(0, timesClosureWasCalled, "unexpected eagerness")
81+
82+
let expected = test.expected.map(OpaqueValue.init)
83+
expectEqualSequence(
84+
expected, result,
85+
stackTrace: SourceLocStack().with(test.loc)
86+
) { $0.value == $1.value }
87+
expectEqual(
88+
test.sequence.count, timesClosureWasCalled,
89+
"iterating lazy flatMap() should call closure once per element")
90+
}
6791
}
6892
% end

0 commit comments

Comments
 (0)