编写函数以便它们可以无缝处理的最佳方法是什么:
- 浮动序列
- 类型为 { ts : DateTime; 的时间戳系列;value: float } seq,其中值在 float 中,称为 value
我特别需要编写函数,例如计算时间序列的平均/方差/随机变换,我只想编写这些函数的 1 个版本。
编写函数以便它们可以无缝处理的最佳方法是什么:
我特别需要编写函数,例如计算时间序列的平均/方差/随机变换,我只想编写这些函数的 1 个版本。
正如评论中所问的,关键问题是您想在数据类型上编写什么样的操作。对于基本的数值运算可能会这样做,但如果您需要一些更复杂的计算,那么编写两个单独的函数可能会更容易。
无论如何,如果你想使用基本的数值运算,那么你需要为你的时间戳类型定义标准的数值运算符。我在最近的一篇文章中对此进行了描述。以下实现+
,除以整数和零:
open System
type TimedFloat =
{ Time : DateTime
Value : float }
static member (+) (tf1, tf2) =
{ Time = DateTime(tf1.Time.Ticks + tf2.Time.Ticks)
Value = tf1.Value + tf2.Value }
static member Zero =
{ Time = DateTime.MinValue
Value = 0.0 }
static member DivideByInt(tf, n) =
{ Time = DateTime(tf.Time.Ticks / int64 n)
Value = tf.Value / float n }
+
运算符有点可疑,因为您最终会得到一些非常大的日期(也许从最后一个开始使用会TimeSpan
更有意义)。但是,一旦定义了运算符,您就可以使用Seq.average
:
[ { Time = DateTime.Now
Value = 3.0 }
{ Time = DateTime.Now.AddDays(2.0)
Value = 10.0 } ]
|> Seq.average
该Seq.average
函数适用于这两种类型,因为它是使用静态成员约束编写的(这意味着它适用于具有必要成员的任何类型)。编写这样的函数比编写普通函数更难,所以我可能不会默认使用这种风格。无论如何,这里有更多示例的介绍,这个SO 答案显示了更多有用的技巧。
编辑 -正如 Jon Harrop 指出的那样,这是一种非常复杂的方法,它只给你带来有限的好处。如果您只需要处理这些值,那么转换为一系列值是一种更好的方法。如果您需要更复杂的计算,那么我认为不值得编写通用函数。为浮点值和时间戳值编写两个单独的函数可能会更容易。
只需将带时间戳的 seq 转换为 float seq,如下所示:
xs
|> Seq.map (fun x -> x.value)