Recursion 如何以F#递归打印年平均数?

Recursion 如何以F#递归打印年平均数?,recursion,f#,functional-programming,Recursion,F#,Functional Programming,好的,我已经解决了这个头疼的问题好几天了,我试着找出如何用文本文件中每行的平均数打印出年份。几天前我问过类似的问题,所以基本上我问的是相同的问题 这样下去。但是,我创建了几个函数。现在,这是我的新问题。为什么我的程序的输出在下图中是这样的?我在代码中注释了几个问题。我一直希望有这样的输出 2010: 3.5788888 2009: 4.697858 This list goes on recursively. 以下是我的更新代码: let ReadFile filename = [ fo

好的,我已经解决了这个头疼的问题好几天了,我试着找出如何用文本文件中每行的平均数打印出年份。几天前我问过类似的问题,所以基本上我问的是相同的问题

这样下去。但是,我创建了几个函数。现在,这是我的新问题。为什么我的程序的输出在下图中是这样的?我在代码中注释了几个问题。我一直希望有这样的输出

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
让我们读取文件名=
[对于System.IO.File.ReadLines(文件名)->行中的行]
让ParseLine(line:string)=
让strings=line.Split('\t')
设strlist=Array.toList(字符串)
let year=System.Int32.Parse(strlist.Head)
让value=List.map System.Double.Parse strlist.Tail
(年份、价值)
让rec打印(年份、值)=
如果值=[],则
()
其他的
printfn“%A:%A”年值。Head
打印(年份、值、尾部)
让avg(values:double list)=//此函数可以计算平均值,但在main、print(firstYear,avg(firstYear1))中执行此操作时,它不起作用
让rec和值累加=
将值与
|[]->accum
|头部:尾部->尾部总和(累积+头部/12.0)
总和值0.0
let rec sum(年份,值:双列表)=
如果值=[],则
0
其他的
值。头+和(年,值。尾)
[]
让主argv=
//将整个文件作为字符串列表读取:
让file=ReadFile“rainment midway.txt”
printfn“**降雨分析程序**”
打印fn“”
//让我们将第一行解析为元组(年份,降雨量值列表),
//然后打印以进行调试:
let(年,值)=ParseLine file.Head
让firstYear=file.Head
让firstYear1=file.Tail
//让data=List.map ParseLine文件//我知道map将是关键,但这如何处理年份及其元素?
//设firstYear=data.Head
//设firstYear=data.Head
//第一年印刷
打印(第一年,第一年1)
//让S=第一年的总和
//printfn“%A”S
//设A=S/12.0
//printfn“%A”A
//完成:
打印fn“”
打印fn“”
0//返回0=>成功

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

首先回答你的问题

为什么我的程序的输出在下图中是这样的

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

谢谢你的帮助!!!!!但不幸的是,我遇到了这个丑陋的错误,根据Visual Studio的说法,在-let(year,values)=ParseLine el(year,avg values))行上,由于float类型,值有错误消息,而它应该有双列表类型?@CR9191或者ParseLine没有返回(int*double list)(你把avg放在那里了吗?)或者,当您刚刚获得了我复制并粘贴了您在我的Visual Studio上发布的代码的平均值时,其他地方的人希望得到一个列表。也许它与年份和价值之间有某种关系,因为它会专注于计算价值?