6

编写函数以便它们可以无缝处理的最佳方法是什么:

  • 浮动序列
  • 类型为 { ts : DateTime; 的时间戳系列;value: float } seq,其中值在 float 中,称为 value

我特别需要编写函数,例如计算时间序列的平均/方差/随机变换,我只想编写这些函数的 1 个版本。

4

2 回答 2

14

正如评论中所问的,关键问题是您想在数据类型上编写什么样的操作。对于基本的数值运算可能会这样做,但如果您需要一些更复杂的计算,那么编写两个单独的函数可能会更容易。

无论如何,如果你想使用基本的数值运算,那么你需要为你的时间戳类型定义标准的数值运算符。我在最近的一篇文章中对此进行了描述。以下实现+,除以整数和零:

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 指出的那样,这是一种非常复杂的方法,它只给你带来有限的好处。如果您只需要处理这些,那么转换为一系列值是一种更好的方法。如果您需要更复杂的计算,那么我认为不值得编写通用函数。为浮点值和时间戳值编写两个单独的函数可能会更容易。

于 2012-10-24T09:26:54.583 回答
9

只需将带时间戳的 seq 转换为 float seq,如下所示:

xs
|> Seq.map (fun x -> x.value)
于 2012-10-24T09:43:37.190 回答