gpt4 book ai didi

algorithm - 置换函数调用

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:56:02 24 4
gpt4 key购买 nike

我想对数据集运行一系列转换。这些转换的输入和输出在类型方面总是相同的,所以我可以任意选择一个顺序。最后,我想评估不同订单的执行情况(输出数据的质量、计算性能等)。所以我给程序一个文件,其中每一行都包含一个函数标识符,然后我这样运行它:

// read lines of file into plan
for (x <- plan) {

val temp : myDataType

x match {
case "Func_A" => temp = myData.map(y => funcA(y))
case "Func_B" => temp = myData.map(y => funcB(y))
...
}

myData = temp
}

myDataType 是一个不可变 集合,它迫使我使用这些临时变量。 plan 可能包含 20 行/函数标识符,这将导致大量复制操作。所以我正在寻找更好的解决方案。我的梦想是像这样链接所有的 map 函数,其中 write 只是一个收集统计数据并将它们写入磁盘的函数,不需要临时变量:

plan match {
case "Plan_A" => myData.map(x => funcB(x)).map(x => funcA(x)).map(...).write
case "Plan_B" => myData.map(x => funcA(x)).map(...).map(x => funcA(x)).write
...
}

但是,在这种情况下,我需要提前知道所有(至少是我想尝试的)排列,并且会有很多(20 多个函数)。我还研究了编译时/运行时代码生成,但对我来说它看起来有点矫枉过正。

所以也许您有一些想法可以更优雅地解决这个问题。

最佳答案

我认为这里有两件事需要解决。

  1. 将函数链接在一起
  2. 获取函数序列

注意:为简单起见,我假设对 Int 进行操作,因此函数类型为 Int => Int。你说你正在映射到相同的类型。

1。链接

假设您有一系列函数和一些数据,您可以执行以下操作:

...
val plan: Seq[Int => Int] = ... // see my second point
...
val myData = List(1, 2, 3, 4) // immutable List

// Can use compose instead of andThen
val compositeFunc = plan.foldLeft((i: Int) => i)(_ andThen _)
val newData = myData map compositeFunc

请注意,您可以使用 andThencompose ( https://twitter.github.io/scala_school/pattern-matching-and-functional-composition.html ) 组合函数

2。获取函数序列(计划)

您可以通过多种方式执行此操作:

  • 在代码中某处的映射中定义它们
  • 在代码中定义它们并使用反射选择它们
  • 在运行时编译它们

map 中的静态定义

class MyFunctions {
def f1(i: Int): Int = i * 2
def f2(i: Int): Int = i * i
def f3(i: Int): Int = i * i * i

// Hardcoded map from string to function name
// Avoids any reflection
val funMap = Map[String, (Int) => Int](
"f1" -> f1,
"f2" -> f2,
"f3" -> f3
)
}

val funcs = new MyFunctions

val myData = List(1, 2, 3, 4) // immutable List

// Assume you read these from your file
val planFromFile = List("f1", "f3", "f2") // String function names

// Get functions using the hardcoded map
val plan = planFromFile map (name => funcs.funMap(name))

// Can use compose instead of andThen
val compositeFunc = plan.foldLeft((i: Int) => i)(_ andThen _)

// Map the function composition to your data
val newData = myData map compositeFunc

使用反射

import scala.reflect.runtime.{universe => ru}

class MyFunctions {
def f1(i: Int): Int = i * 2
def f2(i: Int): Int = i * i
def f3(i: Int): Int = i * i * i
}

val funcs = new MyFunctions

val myData = List(1, 2, 3, 4) // immutable List

// Assume you read these from your file
val planFromFile = List("f1", "f3", "f2") // String function names

// Acts as a function wrapper that wraps a MethodMirror
// Note that all functions in Scala are objects ((Int => Int) is shorthand for Function1 ...)
class WrappedFunction(mirror: reflect.runtime.universe.MethodMirror) extends (Int => Int) {
override def apply(v1: Int): Int = mirror(v1).asInstanceOf[Int]
}

// Returns function wrappers for each string
// Note for simplicity there is no code dealing with missing function , errors etc.
def getFunctions(names: Seq[String]): Seq[Int => Int] =
names.map(s => new WrappedFunction(ru.runtimeMirror(funcs.getClass.getClassLoader)
.reflect(funcs)
.reflectMethod(ru.typeOf[MyFunctions]
.decl(ru.TermName(s)).asMethod)))


val reflectedFunctions = getFunctions(planFromFile)

// Compose them from the generated functions
val compositeFunc2 = reflectedFunctions.foldLeft((i: Int) => i)(_ andThen _)

// Generate data
val newData2 = myData map compositeFunc2

我没有谈到在运行时编译,我假设这不是您的用例。

您还可以组合这些方法并使用反射生成 map 。

编辑 显然你也可以使用模式匹配而不是那个映射..像这样:

def fromName(name: String): Int => Int = name match {
case "f1" => f1
case "f2" => f2
case "f3" => f3
case _ => throw new IllegalArgumentException("booooom!")
}

有关反射的更多信息,请参阅文档:http://docs.scala-lang.org/overviews/reflection/overview.html

关于algorithm - 置换函数调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36718437/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com