我的F#代码比同等的python代码长得多,有什么不对吗?

Has*_*sef 0 f#

我正在将现有python代码转换为F#增加了太多的行数,不确定我是否做错了,或者有一个想要优化它的方法:

Array想要处理这个:

let series = [|30;21;29;31;40;48;53;47;37;39;31;29;17;9;20;24;27;35;41;38;
          27;31;27;26;21;13;21;18;33;35;40;36;22;24;21;20;17;14;17;19;
          26;29;40;31;20;24;18;26;17;9;17;21;28;32;46;33;23;28;22;27;
          18;8;17;21;31;34;44;38;31;30;26;32|]
Run Code Online (Sandbox Code Playgroud)

Python它是:

series = [30,21,29,31,...,26,32]
Run Code Online (Sandbox Code Playgroud)

第1部分

Python我这个:

def initial_seasonal_components(series, slen):
    seasonals = {}
    season_averages = []
    n_seasons = int(len(series)/slen)
    # compute season averages
    for j in range(n_seasons):
        season_averages.append(sum(series[slen*j:slen*j+slen])/float(slen))
Run Code Online (Sandbox Code Playgroud)

转换成F#我最终得到这个:

open System.Collections.Generic 
let initial_seasonal_components (series : int []) (slen : int) : Dictionary<int, double>  =
    let seasonals = new Dictionary<int, double>()
    let mutable seasonAverages = []
    let nSeasons = series.Length / slen 
    // compute season averages
    for i in 0 .. nSeasons-1 do
        seasonAverages  <- 
            series
                |> Array.sub <|| (slen * i, slen)
                |> Array.sum
                |> float
                |> fun s -> s / (slen |> float)
                |> fun e -> [e]
                |> List.append seasonAverages 
Run Code Online (Sandbox Code Playgroud)

第2部分

Python我这个:

for i in range(slen):
    sum_of_vals_over_avg = 0.0
    for j in range(n_seasons):
        sum_of_vals_over_avg += series[slen*j+i]-season_averages[j]
    seasonals[i] = sum_of_vals_over_avg/n_seasons
Run Code Online (Sandbox Code Playgroud)

转换成F#我最终得到这个:

for i in 0 .. slen-1 do
    let mutable sumOfValsOverAvg = 0.0
    for j in 0 .. nSeasons-1 do
        sumOfValsOverAvg <- 
            series 
                |> Array.item (slen*j+i)
                |> float
                |> fun el -> el + sumOfValsOverAvg - seasonAverages.[j]

    seasonals.Add (i, sumOfValsOverAvg / (nSeasons |> float))
Run Code Online (Sandbox Code Playgroud)

我在这里做错了什么,或者这是我能得到的优化代码!!

UPDATE

下面从全"Python`代码在这里:

series = [30,21,29,31,40,48,53,47,37,39,31,29,17,9,20,24,27,35,41,38,
          27,31,27,26,21,13,21,18,33,35,40,36,22,24,21,20,17,14,17,19,
          26,29,40,31,20,24,18,26,17,9,17,21,28,32,46,33,23,28,22,27,
          18,8,17,21,31,34,44,38,31,30,26,32]

def initial_seasonal_components(series, slen):
    seasonals = {}
    season_averages = []
    n_seasons = int(len(series)/slen)
    # compute season averages
    for j in range(n_seasons):
        season_averages.append(sum(series[slen*j:slen*j+slen])/float(slen))
    sarr = [str(a) for a in season_averages]
    print(", " . join(sarr))
    # compute initial values
    for i in range(slen):
        sum_of_vals_over_avg = 0.0
        for j in range(n_seasons):
            sum_of_vals_over_avg += series[slen*j+i]-season_averages[j]
        seasonals[i] = sum_of_vals_over_avg/n_seasons

    return seasonals
Run Code Online (Sandbox Code Playgroud)

在这里我的等效F#代码:

open System.Collections.Generic  // for Dictionary

let series = [|30;21;29;31;40;48;53;47;37;39;31;29;17;9;20;24;27;35;41;38;
          27;31;27;26;21;13;21;18;33;35;40;36;22;24;21;20;17;14;17;19;
          26;29;40;31;20;24;18;26;17;9;17;21;28;32;46;33;23;28;22;27;
          18;8;17;21;31;34;44;38;31;30;26;32|]

let initialAeasonalComponents (series : int []) slen : Dictionary<int, double>  =
    let seasonals = new Dictionary<int, double>()
    let mutable seasonAverages = []
    let nSeasons = series.Length / slen 
    // compute season averages
    for i in 0 .. nSeasons-1 do
        seasonAverages  <- 
            series
                |> Array.sub <|| (slen * i, slen)
                |> Array.sum
                |> float
                |> fun s -> s / (slen |> float)
                |> fun e -> [e]
                |> List.append seasonAverages 

    printfn "Seasons Averageß: \n %A" seasonAverages
    // compute initial values
    for i in 0 .. slen-1 do
        let mutable sumOfValsOverAvg = 0.0
        for j in 0 .. nSeasons-1 do
            sumOfValsOverAvg <- 
                series 
                    |> Array.item (slen*j+i)
                    |> float
                    |> fun el -> el + sumOfValsOverAvg - seasonAverages.[j]

        seasonals.Add (i, sumOfValsOverAvg / (nSeasons |> float))
    printfn "Seasons Averageß: \n %A" seasonals
    seasonals

initialAeasonalComponents series 12
Run Code Online (Sandbox Code Playgroud)

Gus*_*Gus 6

你需要以不同的方式思考,在F#中,mutability不是默认的.

对于第1部分,您可以这样做:

open System.Collections.Generic 
let initial_seasonal_components (series : int []) (slen : int) =
    let seasonals = new Dictionary<int, double>()
    series |> Array.map float |> Array.chunkBySize slen |> Array.map Array.average
Run Code Online (Sandbox Code Playgroud)

对于第2部分,您还可以采用不同的方法:

[|0..slen-1|] 
    |> Array.map (fun i -> 
            i, Array.zip grouped seasonAverages
            |> Array.fold (fun s (els, av) -> els.[i] + s - av) 0.)
    |> Array.map (fun (i, x) -> i, x / float nSeasons)
    |> dict
Run Code Online (Sandbox Code Playgroud)

结合所有部分,你可以像这样写:

let initialAeasonalComponents (series : int []) slen : IDictionary<int, double>  =
    let nSeasons = float  (series.Length / slen)
    let grouped = series |> Array.map float |> Array.chunkBySize slen
    let seasonAverages = grouped |> Array.map Array.average
    Array.init slen (fun i -> i, (Array.zip grouped seasonAverages 
                                    |> Array.fold (fun s (els, av) -> els.[i] + s - av) 0.)
                                        / nSeasons) |> dict
Run Code Online (Sandbox Code Playgroud)

请注意,与Python方法的主要区别在于我们使用更高阶函数,并且我们不使用可变性,这使得更容易推理代码.

还要注意,现在F#代码甚至比Python更短;)