具有因变量的 Scala 映射
Scala map with dependent variables
在 scala 中,我有一个函数列表,return 一个值。函数执行的顺序很重要,因为函数 n
的参数是函数 n-1
.
的输出
这提示使用 foldLeft
,类似于:
val base: A
val funcs: Seq[Function[A, A]]
funcs.foldLeft(base)(x, f) => f(x)
(详情:类型A
实际上是一个Spark DataFrame)。
但是,每个函数的结果是互斥的,最后我想要每个函数的所有结果的并集。
这提示使用 map
,类似于:
funcs.map(f => f(base)).reduce(_.union(_)
但是这里每个函数都应用到base
这不是我想要的。
短:一个可变长度的有序函数列表需要return一个等长的return值列表,其中每个值n-1
是函数[=的输入13=](从 base
开始,其中 n=0
)。这样可以连接结果值。
我怎样才能做到这一点?
编辑
示例:
case class X(id:Int, value:Int)
val base = spark.createDataset(Seq(X(1, 1), X(2, 2), X(3, 3), X(4, 4), X(5, 5))).toDF
def toA = (x: DataFrame) => x.filter('value.mod(2) === 1).withColumn("value", lit("a"))
def toB = (x: DataFrame) => x.withColumn("value", lit("b"))
val a = toA(base)
val remainder = base.join(a, Seq("id"), "leftanti")
val b = toB(remainder)
a.union(b)
+---+-----+
| id|value|
+---+-----+
| 1| a|
| 3| a|
| 5| a|
| 2| b|
| 4| b|
+---+-----+
这应该适用于任意数量的函数(例如 toA
、toB
... toN
。每次计算前一个结果的余数并将其传递给下一个函数。最后一个联合被应用于所有结果。
我有一个使用普通集合的简化解决方案,但同样的原则适用。
val list: List[Int] = List(1, 2, 3, 4, 5)
val funcs: Seq[Function[List[Int], List[Int]]] = Seq(times2, by2)
funcs.foldLeft(list) { case(collection, func) => func(collection) } foreach println // prints 1 2 3 4 5
def times2(l: List[Int]): List[Int] = l.map(_ * 2)
def by2(l: List[Int]): List[Int] = l.map(_ / 2)
如果您希望将单个缩减值作为最终输出,则此解决方案不适用,例如单身Int
;因此,这可以作为:
F[B] -> F[B] -> F[B]
而不是 F[B] -> F[B] -> B
;虽然我想这就是你需要的。
Seq
已经有一个开箱即用的方法 scanLeft
:
funcs.scanLeft(base)((acc, f) => f(acc)).tail
如果您不想包含 base
,请务必删除 scanLeft
结果的第一个元素。
只使用 foldLeft 也是可以的:
funcs.foldLeft((base, List.empty[A])){ case ((x, list), f) =>
val res = f(x)
(res, res :: list)
}._2.reverse.reduce(_.union(_))
或者:
funcs.foldLeft((base, Vector.empty[A])){ case ((x, list), f) =>
val res = f(x)
(res, list :+ res)
}._2.reduce(_.union(_))
诀窍就是在fold
里面累积成一个Seq
。
示例:
scala> val base = 7
base: Int = 7
scala> val funcs: List[Int => Int] = List(_ * 2, _ + 3)
funcs: List[Int => Int] = List($$Lambda72/1298658703@7d46af18, $$Lambda73/107346281@5470fb9b)
scala> funcs.foldLeft((base, Vector.empty[Int])){ case ((x, list), f) =>
| val res = f(x)
| (res, list :+ res)
| }._2
res8: scala.collection.immutable.Vector[Int] = Vector(14, 17)
scala> .reduce(_ + _)
res9: Int = 31
在 scala 中,我有一个函数列表,return 一个值。函数执行的顺序很重要,因为函数 n
的参数是函数 n-1
.
这提示使用 foldLeft
,类似于:
val base: A
val funcs: Seq[Function[A, A]]
funcs.foldLeft(base)(x, f) => f(x)
(详情:类型A
实际上是一个Spark DataFrame)。
但是,每个函数的结果是互斥的,最后我想要每个函数的所有结果的并集。
这提示使用 map
,类似于:
funcs.map(f => f(base)).reduce(_.union(_)
但是这里每个函数都应用到base
这不是我想要的。
短:一个可变长度的有序函数列表需要return一个等长的return值列表,其中每个值n-1
是函数[=的输入13=](从 base
开始,其中 n=0
)。这样可以连接结果值。
我怎样才能做到这一点?
编辑 示例:
case class X(id:Int, value:Int)
val base = spark.createDataset(Seq(X(1, 1), X(2, 2), X(3, 3), X(4, 4), X(5, 5))).toDF
def toA = (x: DataFrame) => x.filter('value.mod(2) === 1).withColumn("value", lit("a"))
def toB = (x: DataFrame) => x.withColumn("value", lit("b"))
val a = toA(base)
val remainder = base.join(a, Seq("id"), "leftanti")
val b = toB(remainder)
a.union(b)
+---+-----+
| id|value|
+---+-----+
| 1| a|
| 3| a|
| 5| a|
| 2| b|
| 4| b|
+---+-----+
这应该适用于任意数量的函数(例如 toA
、toB
... toN
。每次计算前一个结果的余数并将其传递给下一个函数。最后一个联合被应用于所有结果。
我有一个使用普通集合的简化解决方案,但同样的原则适用。
val list: List[Int] = List(1, 2, 3, 4, 5)
val funcs: Seq[Function[List[Int], List[Int]]] = Seq(times2, by2)
funcs.foldLeft(list) { case(collection, func) => func(collection) } foreach println // prints 1 2 3 4 5
def times2(l: List[Int]): List[Int] = l.map(_ * 2)
def by2(l: List[Int]): List[Int] = l.map(_ / 2)
如果您希望将单个缩减值作为最终输出,则此解决方案不适用,例如单身Int
;因此,这可以作为:
F[B] -> F[B] -> F[B]
而不是 F[B] -> F[B] -> B
;虽然我想这就是你需要的。
Seq
已经有一个开箱即用的方法 scanLeft
:
funcs.scanLeft(base)((acc, f) => f(acc)).tail
如果您不想包含 base
,请务必删除 scanLeft
结果的第一个元素。
只使用 foldLeft 也是可以的:
funcs.foldLeft((base, List.empty[A])){ case ((x, list), f) =>
val res = f(x)
(res, res :: list)
}._2.reverse.reduce(_.union(_))
或者:
funcs.foldLeft((base, Vector.empty[A])){ case ((x, list), f) =>
val res = f(x)
(res, list :+ res)
}._2.reduce(_.union(_))
诀窍就是在fold
里面累积成一个Seq
。
示例:
scala> val base = 7
base: Int = 7
scala> val funcs: List[Int => Int] = List(_ * 2, _ + 3)
funcs: List[Int => Int] = List($$Lambda72/1298658703@7d46af18, $$Lambda73/107346281@5470fb9b)
scala> funcs.foldLeft((base, Vector.empty[Int])){ case ((x, list), f) =>
| val res = f(x)
| (res, list :+ res)
| }._2
res8: scala.collection.immutable.Vector[Int] = Vector(14, 17)
scala> .reduce(_ + _)
res9: Int = 31