使用什么类型在 Scala 中存储内存中的可变数据表? [英] What type to use to store an in-memory mutable data table in Scala?
问题描述
每次调用函数时,如果给定参数值集的结果尚未记忆,我想将结果放入内存表中.一列用于存储结果,其他列用于存储参数值.
Each time a function is called, if it's result for a given set of argument values is not yet memoized I'd like to put the result into an in-memory table. One column is meant to store a result, others to store arguments values.
我该如何最好地实现这一点?参数有多种类型,包括一些枚举.
How do I best implement this? Arguments are of diverse types, including some enums.
在 C# 中,我通常使用 DataTable.Scala 中是否有等价物?
In C# I'd generally use DataTable. Is there an equivalent in Scala?
推荐答案
你可以使用 mutable.Map[TupleN[A1, A2, ..., AN], R]
,或者如果内存是一个问题,一个 WeakHashMap[1].下面的定义(建立在来自 michid 的博客的记忆代码之上)允许您轻松记住具有多个参数的函数.例如:
You could use a mutable.Map[TupleN[A1, A2, ..., AN], R]
, or if memory is a concern, a WeakHashMap[1]. The definitions below (built on the memoization code from michid's blog) allow you to easily memoize functions with multiple arguments. For example:
import Memoize._
def reallySlowFn(i: Int, s: String): Int = {
Thread.sleep(3000)
i + s.length
}
val memoizedSlowFn = memoize(reallySlowFn _)
memoizedSlowFn(1, "abc") // returns 4 after about 3 seconds
memoizedSlowFn(1, "abc") // returns 4 almost instantly
定义:
/**
* A memoized unary function.
*
* @param f A unary function to memoize
* @param [T] the argument type
* @param [R] the return type
*/
class Memoize1[-T, +R](f: T => R) extends (T => R) {
import scala.collection.mutable
// map that stores (argument, result) pairs
private[this] val vals = mutable.Map.empty[T, R]
// Given an argument x,
// If vals contains x return vals(x).
// Otherwise, update vals so that vals(x) == f(x) and return f(x).
def apply(x: T): R = vals getOrElseUpdate (x, f(x))
}
object Memoize {
/**
* Memoize a unary (single-argument) function.
*
* @param f the unary function to memoize
*/
def memoize[T, R](f: T => R): (T => R) = new Memoize1(f)
/**
* Memoize a binary (two-argument) function.
*
* @param f the binary function to memoize
*
* This works by turning a function that takes two arguments of type
* T1 and T2 into a function that takes a single argument of type
* (T1, T2), memoizing that "tupled" function, then "untupling" the
* memoized function.
*/
def memoize[T1, T2, R](f: (T1, T2) => R): ((T1, T2) => R) =
Function.untupled(memoize(f.tupled))
/**
* Memoize a ternary (three-argument) function.
*
* @param f the ternary function to memoize
*/
def memoize[T1, T2, T3, R](f: (T1, T2, T3) => R): ((T1, T2, T3) => R) =
Function.untupled(memoize(f.tupled))
// ... more memoize methods for higher-arity functions ...
/**
* Fixed-point combinator (for memoizing recursive functions).
*/
def Y[T, R](f: (T => R) => T => R): (T => R) = {
lazy val yf: (T => R) = memoize(f(yf)(_))
yf
}
}
定点组合器 (Memoize.Y
) 使记忆递归函数成为可能:
The fixed-point combinator (Memoize.Y
) makes it possible to memoize recursive functions:
val fib: BigInt => BigInt = {
def fibRec(f: BigInt => BigInt)(n: BigInt): BigInt = {
if (n == 0) 1
else if (n == 1) 1
else (f(n-1) + f(n-2))
}
Memoize.Y(fibRec)
}
[1] WeakHashMap 不能很好地用作缓存.请参阅 http://www.codeinstructions.com/2008/09/weakhashmap-is-not-cache-understanding.html 和 这个相关问题.
[1] WeakHashMap does not work well as a cache. See http://www.codeinstructions.com/2008/09/weakhashmap-is-not-cache-understanding.html and this related question.
这篇关于使用什么类型在 Scala 中存储内存中的可变数据表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!