FP - Condense和'nice'代码

时间:2011-05-07 11:45:09

标签: f# functional-programming

在大多数情况下,在F#中编写代码会导致非常简洁的直观工作。这段代码对我来说看起来有点迫切和不方便。

  • times是一个浮点值数组

文件times.csv内的行总是这样:

Mai 06 2011 05:43:45 nachm.,00:22.99
Mai 04 2011 08:59:12 nachm.,00:22.73
Mai 04 2011 08:58:27 nachm.,00:19.38
Mai 04 2011 08:57:54 nachm.,00:18.00
  • average生成值的平均值,删除最低和最高时间
  • getAllSubsetsOfLengthN创建一系列长度为n的所有连续子集。是否有一个'更好'的解决方案?或者在F#核心内部已经存在类似内容?
  • bestAverageOfN找到所有子集的最低平均值

let times =
    File.ReadAllLines "times.csv"
    |> Array.map (fun l -> float (l.Substring((l.LastIndexOf ':') + 1)))
let average set =
    (Array.sum set - Array.min set - Array.max set) / float (set.Length - 2)
let getAllSubsetsOfLengthN n (set:float list) =
    seq { for i in [0 .. set.Length - n] -> set
                                            |> Seq.skip i
                                            |> Seq.take n }
let bestAverageOfN n =
    times
    |> Array.toList
    |> getAllSubsetsOfLengthN n
    |> Seq.map (fun t -> t
                         |> Seq.toArray
                         |> average)
    |> Seq.min

我正在寻找的是更好,更短或更简单的解决方案。当然,每个有用的帖子都会被投票赞成:)

4 个答案:

答案 0 :(得分:4)

我猜,getAllSubsetsOfLengthN可以用Seq.windowed替换

所以bestAverageOfN看起来像:

let bestAverageOfN n =
    times
    |> Seq.windowed n
    |> Seq.map average
    |> Seq.min

答案 1 :(得分:3)

没有多想,你可以做一些基本的功能重构。例如,在bestAverageOfN的计算中,您可以使用函数组合:

let bestAverageOfN n =
    times
    |> Array.toList
    |> getAllSubsetsOfLengthN n
    |> Seq.map (Seq.toArray >> average)
    |> Seq.min

除了这个以及desco的建议之外,我认为我不会改变任何事情。如果您不在代码中的任何位置使用特殊的average函数,则可以将其作为lambda函数内联编写,但这实际上取决于您的个人偏好。

仅仅为了一般性,我可能会times bestAverageOfN的论点:

let bestAverageOfN n times =
    times
    |> Seq.windowed n
    |> Seq.map (fun set ->
           (Array.sum set - Array.min set - Array.max set) / float (set.Length - 2))
    |> Seq.min

答案 2 :(得分:2)

由于你提到正则表达式来解析你的输入,我想我会告诉你这样的解决方案。它可能有点矫枉过正,但它也是一个更实用的解决方案,因为正则表达式是声明性的,而子串的东西更为必要。正则表达式也很好,因为如果输入的结构发生变化,索引子字符串的内容会变得混乱,我会更容易增长,并且我会尽量避免它。

首先是几个活跃的模式,

open System.Text.RegularExpressions
let (|Groups|_|) pattern input =
    let m = Regex.Match(input, pattern)
    if m.Success then
        Some([for g in m.Groups -> g.Value] |> List.tail)
    else
        None

open System
let (|Float|_|) input =
    match Double.TryParse(input) with
    | true, value -> Some(value)
    | _ -> None

采用@ ildjarn的times实施:

let times =
    File.ReadAllLines "times.csv"
    |> Array.map (function Groups @",.*?:(.*)$" [Float(value)] -> value)

答案 3 :(得分:1)

由于bestAversageOfN已经涵盖,所以这是times的替代实现:

let times =
    File.ReadAllLines "times.csv"
    |> Array.map (fun l -> l.LastIndexOf ':' |> (+) 1 |> l.Substring |> float)