New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[stdlib] SR-361: Implement SE008: Add Lazy flatMap for Seq of Optionals #2461
Changes from 1 commit
1afa93b
408e8c7
b7329df
9af775b
7dc71d0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,26 @@ extension LazySequenceProtocol { | |
FlattenSequence<LazyMapSequence<Elements, SegmentOfResult>>> { | ||
return self.map(transform).flatten() | ||
} | ||
|
||
/// Returns a `LazyMapSequence` containing the concatenated non-nil | ||
/// results of mapping transform over this `Sequence`. The elements of | ||
/// the result are computed lazily, each time they are read. | ||
/// | ||
/// Use this method to receive only nonoptional values when your | ||
/// transformation produces an optional value. | ||
/// | ||
/// - Parameter transform: A closure that accepts an element of this | ||
/// sequence as its argument and returns an optional value. | ||
@warn_unused_result | ||
public func flatMap<U>( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you change If you feel like doing so, could you also change the names of generic type parameters in the eager There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's no problem |
||
_ transform: (Self.Elements.Iterator.Element) -> U? | ||
) -> LazyMapSequence< | ||
LazyFilterSequence< | ||
LazyMapSequence<Self.Elements, U?>>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you drop There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also no problem |
||
U | ||
> { | ||
return self.map(transform).filter { $0 != nil }.map { $0! } | ||
} | ||
} | ||
|
||
extension LazyCollectionProtocol { | ||
|
@@ -42,6 +62,26 @@ extension LazyCollectionProtocol { | |
> { | ||
return self.map(transform).flatten() | ||
} | ||
|
||
/// Returns a `LazyMapCollection` containing the concatenated non-nil | ||
/// results of mapping transform over this collection. The elements of | ||
/// the result are computed lazily, each time they are read. | ||
/// | ||
/// Use this method to receive only nonoptional values when your | ||
/// transformation produces an optional value. | ||
/// | ||
/// - Parameter transform: A closure that accepts an element of this | ||
/// collection as its argument and returns an optional value. | ||
@warn_unused_result | ||
public func flatMap<U>( | ||
_ transform: (Self.Elements.Iterator.Element) -> U? | ||
) -> LazyMapCollection< | ||
LazyFilterCollection< | ||
LazyMapCollection<Self.Elements, U?>>, | ||
U | ||
> { | ||
return self.map(transform).filter { $0 != nil }.map { $0! } | ||
} | ||
} | ||
|
||
extension LazyCollectionProtocol | ||
|
@@ -67,4 +107,48 @@ extension LazyCollectionProtocol | |
>> { | ||
return self.map(transform).flatten() | ||
} | ||
|
||
/// Returns a `LazyMapBidirectionalCollection` containing the concatenated non-nil | ||
/// results of mapping transform over this collection. The elements of | ||
/// the result are computed lazily, each time they are read. | ||
/// | ||
/// Use this method to receive only nonoptional values when your | ||
/// transformation produces an optional value. | ||
/// | ||
/// - Parameter transform: A closure that accepts an element of this | ||
/// collection as its argument and returns an optional value. | ||
public func flatMap<U>( | ||
_ transform: (Self.Elements.Iterator.Element) -> U? | ||
) -> LazyMapBidirectionalCollection< | ||
LazyFilterBidirectionalCollection< | ||
LazyMapBidirectionalCollection<Self.Elements, U?>>, | ||
U | ||
> { | ||
return self.map(transform).filter { $0 != nil }.map { $0! } | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The overloads for Sequence, Collection and BidirectionalCollection look very similar -- do you want to try gyb'ing them? |
||
} | ||
|
||
extension LazyCollectionProtocol | ||
where | ||
Self : RandomAccessCollection, | ||
Elements : RandomAccessCollection | ||
{ | ||
/// Returns a `LazyMapRandomAccessCollection` containing the concatenated non-nil | ||
/// results of mapping transform over this collection. The elements of | ||
/// the result are computed lazily, each time they are read. | ||
/// | ||
/// Use this method to receive only nonoptional values when your | ||
/// transformation produces an optional value. | ||
/// | ||
/// - Parameter transform: A closure that accepts an element of this | ||
/// collection as its argument and returns an optional value. | ||
public func flatMap<U>( | ||
_ transform: (Self.Elements.Iterator.Element) -> U? | ||
) -> LazyMapRandomAccessCollection< | ||
LazyFilterRandomAccessCollection< | ||
LazyMapRandomAccessCollection<Self.Elements, U?>>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can't have this overload because moving the index of the returned collection by n steps is not O(1). |
||
U | ||
> { | ||
return self.map(transform).filter { $0 != nil }.map { $0! } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1161,6 +1161,20 @@ tests.test("LazyFilterBidirectionalCollection/AssociatedTypes") { | |
indicesType: DefaultBidirectionalIndices<Subject>.self) | ||
} | ||
|
||
tests.test("LazyFilterRandomAccessCollection/AssociatedTypes") { | ||
typealias Base = MinimalRandomAccessCollection<OpaqueValue<Int>> | ||
typealias Subject = LazyFilterRandomAccessCollection<Base> | ||
expectRandomAccessCollectionAssociatedTypes( | ||
collectionType: Subject.self, | ||
iteratorType: LazyFilterIterator<Base.Iterator>.self, | ||
// FIXME(ABI): SubSequence should be `LazyFilterRandomAccessCollection<Base.Slice>`. | ||
subSequenceType: RandomAccessSlice<Subject>.self, | ||
indexType: LazyFilterIndex<Base>.self, | ||
indexDistanceType: Base.IndexDistance.self, | ||
indicesType: DefaultRandomAccessIndices<Subject>.self) | ||
} | ||
|
||
|
||
tests.test("lazy.filter/TypeInference") { | ||
let baseArray: [OpaqueValue<Int>] = (0..<10).map(OpaqueValue.init) | ||
do { | ||
|
@@ -1190,7 +1204,7 @@ tests.test("lazy.filter/TypeInference") { | |
var filtered = MinimalRandomAccessCollection(elements: baseArray) | ||
.lazy.filter { _ in true } | ||
expectType( | ||
LazyFilterBidirectionalCollection< | ||
LazyFilterRandomAccessCollection< | ||
MinimalRandomAccessCollection<OpaqueValue<Int>> | ||
>.self, | ||
&filtered) | ||
|
@@ -1283,5 +1297,22 @@ do { | |
} | ||
} | ||
|
||
runAllTests() | ||
% for Traversal in TRAVERSALS: | ||
% TraversalCollection = collectionForTraversal(Traversal) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use two spaces for indentation (no tabs). |
||
tests.test("${TraversalCollection}/lazy/flatMap") { | ||
let sample = (0..<100) | ||
let expected = sample.filter { $0 % 3 != 0 }.map { String($0) } | ||
let base = Minimal${TraversalCollection}(elements: sample).lazy | ||
|
||
var calls = 0 | ||
let mapped = sample.lazy.flatMap { (x) -> String? in | ||
calls += 1 | ||
return x % 3 != 0 ? String(x) : nil | ||
} | ||
expectEqual(0, calls, "unexpected eagerness in \(base.dynamicType).flatMap") | ||
|
||
checkSequence(expected, mapped, resiliencyChecks: .none) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the test should go into |
||
%end | ||
|
||
runAllTests() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The summary of the doc comment should be a single sentence. CC @natecook1000
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The second sentence could just be removed, since that's covered by the
Lazy...
type of the return.