Closed Qata closed 3 years ago
That would be a useful addition!
The current alternative could be code golfed down to this though:
let value = ["Hello", "10"].lazy.compactMap(Int.init).first
What you're proposing is fairly close to Scala's collectFirst
by the way: https://www.scala-lang.org/api/current/scala/collection/Seq.html#collectFirst[B](pf:PartialFunction[A,B]):Option[B]
I'm bringing it up mostly because I really really miss collect
(which is the same but over the entire collection), it's tremendously useful.
func collect<Result>(_ transform: (Element) -> Result?) -> [Result]
func collectFirst<Result>(_ transform: (Element) -> Result?) -> Result?
Perhaps collect
and collectFirst
could be a thing to consider?
@ktoso I think you mixed up the type signatures? And if you did, isn't func collect<R>(_ transform: (Element) -> R?) -> [R]
what we already know as compactMap(_:)
?
Ah thanks, fixed the swapped signatures.
And if you did, isn't func collect
( transform: (Element) -> R?) -> [R] what we already know as compactMap(:)?
Hmm, I guess by "swift-ifying" the function I dropped the a core feature of collect
actually: the partial function. So since we don't have those in Swift, the collect kind of misses a lot of the power and devolves into a devolves into a compactMap
as you rightfully observed there hm -- too bad hm. For reference how usage looks like there:
(1 :: 2 :: 3 :: 10 :: Nil) collect { // PartialFunction can be expressed as pattern match
case 1 => "yes-1"
case 10 => "yes-10"
} // List("yes-1", "yes-10")
Feel free to ignore my sidetracking comment 🙂
Big +1, I've wanted (and used) this operation for years. The hardest part about adding it is coming up with a proper name. Lately I've been calling it firstMap
, mainly because I believe "first" and "map" should both be part of the name, and mapFirst
is not really a serious contender.
Other suggestions I've heard go around:
compactMapFirst
first(mapping:)
firstNonNil
firstSome
I'm aware of prior art in just 2 other languages:
find_map
in Rust (Swift's first(where:)
is called find
in Rust)firstJust
in Haskell (Swift's Option.some
is called Just
in Haskell)This feels right on the cusp, given that it's composable via .lazy.compactMap(f).first
, as pointed out by @pyrtsa. On the plus side are these factors:
Any other notes in favor? Is there a correctness or performance improvement over the .lazy
approach?
given that it's composable via
.lazy.compactMap(f).first
It is often overlooked that calling this on a (non-Collection
) Sequence
isn't lazy, because first
doesn't exist on Sequence
, so that compactMap
is secretly the eager one returning an array.
It is often overlooked that calling this on a (non-
Collection
)Sequence
isn't lazy, becausefirst
doesn't exist onSequence
, so thatcompactMap
is secretly the eager one returning an array.
That's a great point!
@natecook1000 What's the next step from here? Does naming bike-shedding happen on this issue or on an actual PR?
The name is definitely the trickiest part here, but I think we can add this with our best bet and move forward that way. Let's start with firstNonNil(_:)
and go from there. Thanks!
Let the bikeshedding commence #31
I found myself often having to find the first element in an array that passes an optional initialiser. If I wanted to stick to a purely functional paradigm (which I do, I'm a zealot) I need to do some pretty not-ideal transforms to allow this behaviour without defining a new function.
This could be trivialised with the following (naive) implementation.