什么类型用于在Scala中存储内存中的可变数据表? [英] What type to use to store an in-memory mutable data table in Scala?

查看:130
本文介绍了什么类型用于在Scala中存储内存中的可变数据表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

每次调用一个函数时,如果给定的一组参数值的结果尚未被记忆,我想将结果放入内存表中。一列旨在存储结果,其他列用于存储参数值。



如何最好地实现?参数有多种类型,包括一些枚举。



在C#中,我一般会使用DataTable。 Scala中有一个等价物吗?

解决方案

您可以使用 mutable.Map [TupleN [A1, A2,...,AN],R] ,或者如果内存是关注的话,WeakHashMap [1]。下面的定义(基于 michid的博客的记忆代码)允许您轻松地记录多个参数的函数。例如:

  import Memoize._ 

def trueSlowFn(i:Int,s:String) :Int = {
Thread.sleep(3000)
i + s.length
}

val memoizedSlowFn = memoize(reallySlowFn _)
memoizedSlowFn(1 ,abc)//大约3秒后返回4
memoizedSlowFn(1,abc)//几乎立即返回4

说明:

  / ** 
*记忆一元函数。
*
* @param f记录
* @param的一元函数[T]参数类型
* @param [R]返回类型
* /
class Memoize1 [-T,+ R](f:T => R)extends(T => R){
import scala.collection.mutable
//存储地图(参数,结果)对
private [this] val vals = mutable.Map.empty [T,R]

//给定一个参数x,
//如果vals包含x个返回值(x)。
//否则,更新vals,以便vals(x)== f(x)并返回f(x)。
def apply(x:T):R = vals getOrElseUpdate(x,f(x))
}

对象Memoize {
/ **
*记录一元(单参数)函数。
*
* @param f一元函数记忆
* /
def memoize [T,R](f:T => R):( T => R)= new Memoize1(f)

/ **
*记忆一个二进制(双参数)函数。
*
* @param f要记忆的二进制函数
*
*这可以通过将一个函数转换为两个参数类型
* T1和T2到一个函数采用
*(T1,T2)类型的单个参数,记录tupled函数,然后unupling
* memoized函数。 ((T1,T2)=> R):((T1,T2)=> R)=
功能.upupup(memoize(f.tupled))

/ **
*记忆三元(三参数)函数。
*
* @param f要记忆的三元函数
* /
def memoize [T1,T2,T3,R](f:(T1,T2,T3)= > R):((T1,T2,T3)=> R)=
Function.undupled(memoize(f.tupled))

// ...更多memoize方法用于更高级的功能...

/ **
*定点组合器(用于记忆递归函数)。
* /
def Y [T,R](f:(T => R)=> T => R):(T => R)= {
lazy val yf:(T => R)= memoize(f(yf)(_))
yf
}
}
pre>

定点组合器( Memoize.Y )可以记录递归函数:

  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 此相关问题


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.

In C# I'd generally use DataTable. Is there an equivalent in Scala?

解决方案

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

Definitions:

/**
 * 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
   }
}

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 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆