如何在F#中以递归方式打印年份的平均数?

时间:2015-02-15 18:32:55

标签: recursion f# functional-programming

好的,所以我已经解决了这个问题几天,试图弄清楚如何打印年份,我的文本文件中的每行平均数。几天前我问了这个类似的问题所以我基本上都在问同一个问题,How do I print out lines recursively from a text file along with the average value of total elements from per line?

这种情况继续下去。但是,我创建了几个函数。现在,这是我的新问题。为什么我的程序输出在下图中如下所示?我在我的代码中注释了几个问题。我一直期待输出像

2010: 3.5788888
2009: 4.697858
This list goes on recursively.

Output

这是我更新的代码:

let ReadFile filename =
  [ for line in System.IO.File.ReadLines(filename) -> line ]

let ParseLine (line:string) =
  let strings = line.Split('\t')
  let strlist = Array.toList(strings)
  let year = System.Int32.Parse(strlist.Head)
  let values = List.map System.Double.Parse strlist.Tail
  (year, values)

let rec print (year, values) =
  if values = [] then
    ()
  else
    printfn "%A: %A" year values.Head 
    print (year, values.Tail)

let avg (values:double list) = //this function can compute the average, but it wont work when I do in main, print(firstYear, avg (firstYear1))
    let rec sum values accum =
        match values with
        |  [] -> accum
        |  head :: tail -> sum tail (accum + head/12.0)
    sum values 0.0

let rec sum (year, values:double list) = 
  if values = [] then
    0.0
  else
    values.Head + sum (year, values.Tail)

[<EntryPoint>]
let main argv =
  // read entire file as list of strings:
  let file = ReadFile "rainfall-midway.txt"

  printfn "** Rainfall Analysis Program **"
  printfn ""

  // let's parse first line into tuple (year, list of rainfall values),
  // and then print for debugging:
  let (year, values) = ParseLine file.Head
  let firstYear = file.Head
  let firstYear1 = file.Tail

  //let data = List.map ParseLine file //I know map would be the key, but how does this work with year and its elements?
  //let firstYear = data.Head

  //let firstYear = data.Head
  //print firstYear

  print (firstYear, firstYear1)
  //let S = sum firstYear
  //printfn "%A" S

  //let A = S / 12.0
  //printfn "%A" A

  // done:
  printfn ""
  printfn ""
  0 // return 0 => success

1 个答案:

答案 0 :(得分:1)

您拥有的代码实际上非常接近于为您提供所期望的数据。您可以进行一些更改以简化操作。

首先回答你的问题

  

为什么我的节目输出在下图中如下所示?

这是因为您打印出年份和所有已解析的值(这与打印文件的代码不匹配)。解决此问题的一种简单方法是让ParseLine函数计算平均值。您需要在avg函数之前移动ParseLine,但这应该不是问题。

let avg (values:double list) =
    let rec sum values accum =
        match values with
        |  [] -> accum
        |  head :: tail -> sum tail (accum + head/12.0)
    sum values 0.0

let ReadFile filename =
  [ for line in System.IO.File.ReadLines(filename) -> line ]

let ParseLine (line:string) =
  let strings = line.Split('\t')
  let strlist = Array.toList(strings)
  let year = System.Int32.Parse(strlist.Head)
  let values = List.map System.Double.Parse strlist.Tail
  (year, avg values) // calculate avg here

完成后,您可以使用地图在文件的所有行上运行ParseLine。

let result = file |> List.map ParseLine

然后打印出结果,只需遍历结果列表。

result |> List.iter(fun (year, avgRainfall) -> printfn "%i: %f" year avgRainfall)

那说我们可以完全删除sum和avg函数,并在我们的ParseLine函数中使用fold。

let ParseLine (line:string) =
  let strings = line.Split('\t')
  let strlist = Array.toList(strings)
  let year = System.Int32.Parse(strlist.Head)
  year, (strlist.Tail |> List.fold(fun state el -> (System.Double.Parse el + state)) 0.0) / float strlist.Tail.Length

如果您不想更改ParseLine功能,则可以执行以下操作:

  let result = file |> List.map(fun el -> 
    let (year, values) = ParseLine el
    (year, avg values))