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

How do I print out year with average number recursively in F#?

好吧,为了解决这个令人头疼的问题几天,我试图弄清楚如何从我的文本文件中的每行中打印出年份和平均数。几天前我问过这个类似的问题,所以基本上我在问同样的问题,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.

这是我更新的代码:

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

您拥有的代码实际上非常接近于提供您期望的数据。你可以做一些改变来简化事情。

第一个回答你的问题

Why does my program's output looks like this in the picture below?

这是因为您要打印出年份和所有已解析的值(这与刚刚打印出文件的代码不匹配)。解决这个问题的一个简单方法是让 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))