以单个值收集多个偏函数的结果?
Collect results of multiple partial functions at single value?
假设我有一些可能具有重叠域的部分函数:
val funcs: Seq[PartialFunction[Any, Int]] = Vector(
{ case i: Int if i % 2 == 0 => i*2 }
,
{ case i: Int if i % 2 == 1 => i*3 }
,
{ case i: Int if i % 6 == 0 => i*5 }
)
我想将它们应用于一个值并收集在该值定义的任何结果。我认为有一种优雅的方式可以为此使用 collect
但我能做的最好的是
val num = 66
funcs.collect { case func if func.isDefinedAt(num) => func(num) }
// or
funcs.filter(_.isDefinedAt(num)).map(_(num))
这看起来不太干净。有没有办法使用内置的案例机制来同时测试定义和评估,也许通过将它们与测试值或类似的东西联系起来?
部分函数有一个 lift
方法,如果定义了 PF,则为 Some(res)
,如果未定义,则为 None
。同样通过使用 flatMap
我们基本上可以忽略 None
并只获取 Some
值。
funcs.flatMap { func => func.lift(num) }
如果您喜欢这类东西,也可以压缩:
funcs.flatMap(_.lift(num))
to test definedness and evaluate at the same time
即applyOrElse
。 collect
和 lift
使用它来避免双重计算。
这个递归版本说,应用下一个函数并用它来构建结果,或者继续构建结果的其余部分。
def f(ff: List[PartialFunction[Any, Int]]): List[Int] = ff match {
case hd :: tail => hd.applyOrElse(num, (_: Any) => return f(tail)) :: f(tail)
case _ => Nil
}
这是我第一次在 Scala 中使用 return
。我不得不在索引中查找它。
这种手动构造避免了在 Lifted
、Option
和适应 Option
.
中创建某些对象
scala> :pa
// Entering paste mode (ctrl-D to finish)
val funcs: Seq[PartialFunction[Any, Int]] = Vector(
{ case i: Int if i % 2 == 0 => i*2 }
,
{ case i: Int if i % 2 == 1 => i*3 }
,
{ case i: Int if i % 6 == 0 => i*5 }
)
val num = 66
def f(ff: List[PartialFunction[Any, Int]]): List[Int] = ff match {
case hd :: tail => hd.applyOrElse(num, (_: Any) => return f(tail)) :: f(tail)
case _ => Nil
}
// Exiting paste mode, now interpreting.
funcs: Seq[PartialFunction[Any,Int]] = Vector(<function1>, <function1>, <function1>)
num: Int = 66
f: (ff: List[PartialFunction[Any,Int]])List[Int]
scala> f(funcs.toList)
res0: List[Int] = List(132, 330)
scala> funcs flatMap (_ lift num)
res1: Seq[Int] = Vector(132, 330)
第二个版本只是为同样的想法使用了一个标志。
scala> :pa
// Entering paste mode (ctrl-D to finish)
def f(ff: List[PartialFunction[Any, Int]]): List[Int] = ff match {
case hd :: tail =>
var ok = true
val x = hd.applyOrElse(num, (_: Any) => { ok = false ; 0 })
if (ok) x :: f(tail) else f(tail)
case _ => Nil
}
// Exiting paste mode, now interpreting.
f: (ff: List[PartialFunction[Any,Int]])List[Int]
scala> f(funcs.toList)
res2: List[Int] = List(132, 330)
假设我有一些可能具有重叠域的部分函数:
val funcs: Seq[PartialFunction[Any, Int]] = Vector(
{ case i: Int if i % 2 == 0 => i*2 }
,
{ case i: Int if i % 2 == 1 => i*3 }
,
{ case i: Int if i % 6 == 0 => i*5 }
)
我想将它们应用于一个值并收集在该值定义的任何结果。我认为有一种优雅的方式可以为此使用 collect
但我能做的最好的是
val num = 66
funcs.collect { case func if func.isDefinedAt(num) => func(num) }
// or
funcs.filter(_.isDefinedAt(num)).map(_(num))
这看起来不太干净。有没有办法使用内置的案例机制来同时测试定义和评估,也许通过将它们与测试值或类似的东西联系起来?
部分函数有一个 lift
方法,如果定义了 PF,则为 Some(res)
,如果未定义,则为 None
。同样通过使用 flatMap
我们基本上可以忽略 None
并只获取 Some
值。
funcs.flatMap { func => func.lift(num) }
如果您喜欢这类东西,也可以压缩:
funcs.flatMap(_.lift(num))
to test definedness and evaluate at the same time
即applyOrElse
。 collect
和 lift
使用它来避免双重计算。
这个递归版本说,应用下一个函数并用它来构建结果,或者继续构建结果的其余部分。
def f(ff: List[PartialFunction[Any, Int]]): List[Int] = ff match {
case hd :: tail => hd.applyOrElse(num, (_: Any) => return f(tail)) :: f(tail)
case _ => Nil
}
这是我第一次在 Scala 中使用 return
。我不得不在索引中查找它。
这种手动构造避免了在 Lifted
、Option
和适应 Option
.
scala> :pa
// Entering paste mode (ctrl-D to finish)
val funcs: Seq[PartialFunction[Any, Int]] = Vector(
{ case i: Int if i % 2 == 0 => i*2 }
,
{ case i: Int if i % 2 == 1 => i*3 }
,
{ case i: Int if i % 6 == 0 => i*5 }
)
val num = 66
def f(ff: List[PartialFunction[Any, Int]]): List[Int] = ff match {
case hd :: tail => hd.applyOrElse(num, (_: Any) => return f(tail)) :: f(tail)
case _ => Nil
}
// Exiting paste mode, now interpreting.
funcs: Seq[PartialFunction[Any,Int]] = Vector(<function1>, <function1>, <function1>)
num: Int = 66
f: (ff: List[PartialFunction[Any,Int]])List[Int]
scala> f(funcs.toList)
res0: List[Int] = List(132, 330)
scala> funcs flatMap (_ lift num)
res1: Seq[Int] = Vector(132, 330)
第二个版本只是为同样的想法使用了一个标志。
scala> :pa
// Entering paste mode (ctrl-D to finish)
def f(ff: List[PartialFunction[Any, Int]]): List[Int] = ff match {
case hd :: tail =>
var ok = true
val x = hd.applyOrElse(num, (_: Any) => { ok = false ; 0 })
if (ok) x :: f(tail) else f(tail)
case _ => Nil
}
// Exiting paste mode, now interpreting.
f: (ff: List[PartialFunction[Any,Int]])List[Int]
scala> f(funcs.toList)
res2: List[Int] = List(132, 330)