玩F#,我试图以更实用的方式思考代码.我工作的很大一部分恰好是数字化的,所以我在想这种再教育是否有意义.是否正在以一种功能性的方式编写数字代码,例如试图在圆孔中安装方形钉
例如,让我们拿一个片段来演示大数的弱定律:
open System open System.IO open System.Windows.Forms open System.Windows.Forms.DataVisualization open FSharp.Data open FSharp.Charting open FSharp.Core.Operators open MathNet.Numerics open MathNet.Numerics.LinearAlgebra open MathNet.Numerics.Random open MathNet.Numerics.Distributions open MathNet.Numerics.Statistics let T = 1000 let arr1 = Array.init T (fun i -> float i*0.) for i in 0 .. T-1 do arr1.[i] <- [|for j in 1..i do yield Exponential.Sample(0.1)|] |> Statistics.Mean let arr2 = Array.init T (fun i -> float i*0.) for i in 0 .. T-1 do arr2.[i] <- arr1.[1 .. i] |> Statistics.Mean arr2 |> Chart.Line |> Chart.Show
是否有一种简洁的功能性表达方式?有多少功能范例可以融入到这样的工作中?
不确定问题是否属于主题.谢谢.
我首先不要将对Array.init的调用分开并设置初始值.您可以使用@ s952163在其答案中使用的表单,或者根据您的代码:let arr1 = Array.init T (fun i -> [|for j in 1..i do yield Exponential.Sample 0.1 |] |> Statistics.Mean )
问题是你正在分配中间数组,这是昂贵的 – 而且你无论如何都要在计算平均值之后丢弃它们.替代方案:
let arr1 = Array.init T (fun i -> Exponential.Samples 0.1 |> Seq.take (i+1) |> Seq.average )
现在对于第二部分:您重复计算元素1..i的平均值,这将成为O(n ^ 2)运算.您可以通过使用元素1..i的总和是元素1 .. {i-1}加上第i个元素的总和来在O(n)中求解它.
let sums, _ = arr1 |> Array.mapFold (fun sumSoFar xi -> let s = sumSoFar + xi s, s ) 0.0 let arr2 = sums |> Array.mapi (fun i sumi -> sumi / (float (i + 1)))
当然,你们都可以在一个管道中写出来.
或者,使用库函数Array.scan来计算累积总和,在这种情况下,这将给出长度为T 1的结果,然后从中删除第一个元素:
let arr2 = Array.sub (Array.scan (+) 0.0 arr1) 1 T |> Array.mapi (fun i sumi -> sumi / (float (i + 1)))
或避免中间数组:
Seq.scan (+) 0.0 arr1 |> Seq.skip 1 |> Seq.mapi (fun i sumi -> sumi / (float (i + 1))) |> Seq.toArray