- Proposal: SE-0032
- Author: Lily Ballard
- Review Manager: Chris Lattner
- Status: Implemented (Swift 3.0)
- Decision Notes: Rationale
- Bug: SR-1519
- Previous Revisions: 1
Add a new extension method to Sequence called first(where:) that returns the
found element.
Discussion on swift-evolution started with a proposal with title Add find method to SequenceType
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 Collections you can call index(of:) or index(where:) and pass the resulting
index back into the subscript, but this is a bit awkward. For Sequences,
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