- Proposal: SE-0032
- Author: Kevin Ballard
- Status: Accepted for Swift 3 (Rationale)
- Review manager: Chris Lattner
- Revision: 2
- Previous Revisions: 1
Add a new extension method to Sequence
called first(where:)
that returns the
found element.
Swift-evolution thread: Proposal: Add function SequenceType.find()
It's often useful to find the first element of a sequence that passes some given
predicate. For Collection
s you can call index(of:)
or index(where:)
and pass the resulting
index back into the subscript
, but this is a bit awkward. For Sequence
s,
there's no easy way to do this besides a manual loop that doesn't require
filtering the entire sequence and producing an array.
I have seen people write code like seq.lazy.filter(predicate).first
, but this
doesn't actually work lazily because .first
is only a method on
Collection
, which means the call to filter()
ends up resolving to the
Sequence.filter()
that returns an Array instead of to
LazySequenceProtocol.filter()
that returns a lazy sequence. Users typically aren't
aware of this, which means they end up doing a lot more work than expected.
Extend Sequence
with a method called first(where:)
that takes a predicate and
returns an optional value of the first element that passes the predicate, if
any.
Add the following extension to Sequence
:
extension Sequence {
/// Returns the first element where `predicate` returns `true`, or `nil`
/// if such value is not found.
public func first(where predicate: @noescape (Self.Iterator.Element) throws -> Bool) rethrows -> Self.Iterator.Element? {
for elt in self {
if try predicate(elt) {
return elt
}
}
return nil
}
}
None, this feature is purely additive.
In theory, we might provide an automatic conversion from
seq.filter(predicate).first
or seq.lazy.filter(predicate).first
to
seq.first(where: predicate)
, although the existing code would continue to
compile just fine.
None