Scala是否具有等效于F#的Seq.tryPick函数的效率?

时间:2019-07-23 04:16:01

标签: scala sequence

假设我有一个序列mySeq,该序列由类型为A的元素和类型为f的函数A -> Option<B>组成,并且我想要类型为{{1 }}是将Option<B>应用于序列的所有元素而产生的Some,否则为f(如果未找到这样的结果)。

在F#中,这可以通过tryPick函数来巧妙地处理:

None

在Scala中,我能找到的最好方法是:

mySeq |> Seq.tryPick f

有更好的方法吗?

编辑:即使找到第一个mySeq.iterator.map(f).find(_.isDefined).flatten ,也不能为整个列表计算结果的解决方案。

4 个答案:

答案 0 :(得分:2)

您也可以自己实施:

@tailrec
def tryPick[A, B](fn: A => Option[B], seq: Seq[A]): Option[B] =
  seq match {
    case Nil => None // Only in case an empty sequence was passed initially
    case head +: Nil => fn(head)
    case head +: tail => fn(head) match {
      case Some(output) => Some(output)
      case None => tryPick(fn, tail)
    }
  }

然后像这样使用它:

scala> def myFn(int: Int) = if (int > 2) Some(int) else None
myFn: (int: Int)Option[Int]

scala> tryPick(myFn, List(1, 0, -2, 3))
res0: Option[Int] = Some(3)

答案 1 :(得分:1)

mySeq.iterator.flatMap(a => f(a)).toSeq.headOption

很遗憾,由于.toSeq没有Iterator方法,因此必须调用headOption

但是toSeq返回Stream的{​​{1}},它是惰性计算的,因此不会发生不必要的计算。 <-仅在scala 2.13之前

答案 2 :(得分:1)

tryPick几乎等同于collectFirstcollectFirstPartialFunction一起工作。因此,最接近的可能是:

seq.collectFirst((f _).unlift) // when f is a method

seq.collectFirst(f.unlift) // when f is a function

seq.collectFirst(Function.unlift(f)) // when you're on Scala 2.12 or lower, or just like this better than the previous 2...

看哪:

scala> def f(a: Int) = {println(s"f($a)"); Option.when(a/2*2 == a)("x" * a)}
f: (a: Int)Option[String]

scala> List(1, 2, 3, 4, 5).collectFirst((f _).unlift)
f(1)
f(2)
res1: Option[String] = Some(xx)

答案 3 :(得分:0)

您不需要迭代器 mySeq.map(f)将返回SequenceSome(result)中的None。然后,仅从调用的元素Seq中获得flatten,这样mySeq.map(f).flatten

由于您希望获得第一个结果,因此可以调用head,如果要在Option中包含元素,可以首先调用flatten,但是如果您确实想保留{{ 1}},那么您只需要None就可以得到headSome,所以None