我需要有条件地将函数f1应用于集合中的元素,具体取决于函数f2的结果,该函数将每个元素作为参数并返回一个布尔值。如果f2(e)为真,则将应用f1(e),否则“e”将“按原样”返回。 我的目的是编写一个能够处理任何类型集合的通用函数。
c: C[E] // My collection
f1 = ( E => E ) // transformation function
f2 = ( E => Boolean ) // conditional function
我无法找到解决方案。这是我的想法,但我担心我在高水域
/* Notice this code doesn't compile ~ partially pseudo-code */
conditionallyApply[E,C[_](c: C[E], f2: E => Boolean, f1: E => E): C[E] = {
@scala.annotation.tailrec
def loop(a: C[E], c: C[E]): C[E] = {
c match {
case Nil => a // Here head / tail just express the idea, but I want to use a generic collection
case head :: tail => go(a ++ (if f2(head) f1(head) else head ), tail)
}
}
loop(??, c) // how to get an empty collection of the same type as the one from the input?
}
你们中有人可以启发我吗?
答案 0 :(得分:3)
这看起来像map
的简单Functor
。使用scalaz
:
def condMap[F[_],A](fa: F[A])(f: A => A, p: A => Boolean)(implicit F:Functor[F]) =
F.map(fa)(x => if (p(x)) f(x) else x)
答案 1 :(得分:2)
不知道为什么你需要scalaz才能行走。
// example collection and functions
val xs = 1 :: 2 :: 3 :: 4 :: Nil
def f1(v: Int) = v + 1
def f2(v: Int) = v % 2 == 0
// just conditionally transform inside a map
val transformed = xs.map(x => if (f2(x)) f1(x) else x)
答案 2 :(得分:0)
不使用scalaz,您可以使用CanBuildFrom
模式。这正是标准集合库中使用的内容。当然,在您的具体情况下,这可能是过度设计的,因为对map
的简单调用就足够了。
import scala.collection.generic._
def cmap[A, C[A] <: Traversable[A]](col: C[A])(f: A ⇒ A, p: A ⇒ Boolean)(implicit bf: CanBuildFrom[C[A], A, C[A]]): C[A] = {
val b = bf(col)
b.sizeHint(col)
for (x <- col) if(p(x)) b += f(x) else b += x
b.result
}
现在用法:
scala> def f(i: Int) = 0
f: (i: Int)Int
scala> def p(i: Int) = i % 2 == 0
p: (i: Int)Boolean
scala> cmap(Seq(1, 2, 3, 4))(f, p)
res0: Seq[Int] = List(1, 0, 3, 0)
scala> cmap(List(1, 2, 3, 4))(f, p)
res1: List[Int] = List(1, 0, 3, 0)
scala> cmap(Set(1, 2, 3, 4))(f, p)
res2: scala.collection.immutable.Set[Int] = Set(1, 0, 3)
观察返回类型如何始终与提供的类型相同。
该函数可以很好地封装在一个隐式类中,使用&#34; pimp my library&#34;图案。
答案 3 :(得分:0)
对于这样的事情,您可以使用隐式类。出于这个原因添加它们是为了增强您无法更改的库。
它会像这样工作:
object ImplicitStuff {
implicit class SeqEnhancer[A](s:Seq[A]) {
def transformIf( cond : A => Boolean)( f : A => A ):Seq[A] =
s.map{ x => if(cond(x)) f(x) else x }
}
def main(a:Array[String]) = {
val s = Seq(1,2,3,4,5,6,7)
println(s.transformIf(_ % 2 ==0){ _ * 2})
// result is (1, 4, 3, 8, 5, 12, 7)
}
}
基本上,如果您调用的对象中不存在某个方法(在这种情况下为Seq
),它将检查是否存在实现该方法的隐式类,但是看起来内置方法。