gpt4 book ai didi

F#管道函数执行流程

转载 作者:行者123 更新时间:2023-12-02 08:02:40 25 4
gpt4 key购买 nike

我是 F# 新手,下面的代码是从一个 csv 文件中获取评分 > 9.0 的所有行,然后输出到一个新文件。

但我很难弄清楚完成这项工作需要多少次 for 循环,是所有步骤都在一个 for 循环中完成还是像我在下面强调的那样在 5 个 for 循环中完成?

如果需要 5 个 for 循环来完成工作,它应该在完成第 2 个循环后将整个文件加载到内存中,但整个过程只消耗 14M 内存,比 csv 文件少。

我知道 StreamReader 不会一次性将整个文件加载到内存中,但是下面的代码是如何执行的呢?

提前谢谢...

let ratings = @"D:\Download\IMDB\csv\title.ratings.csv"
let rating9 = @"D:\Download\IMDB\csv\rating9.csv"

let readCsv reader =
Seq.unfold (fun (r:StreamReader) -> // 1st for loop
match r.EndOfStream with
| true -> None
| false -> Some (r.ReadLine(), r)) reader

let toTuple = fun (s:string) ->
let ary = s.Split(',')
(string ary.[0], float ary.[1], int ary.[2])

using (new StreamReader(ratings)) (fun sr ->
use sw = new StreamWriter(rating9)
readCsv sr
|> Seq.map toTuple // 2nd for loop
|> Seq.filter (fun (_, r, _) -> r > 9.0) // 3rd for loop
|> Seq.sortBy (fun (_, r, _) -> r) // 4th for loop
|> Seq.iter (fun (t, r, s) -> // 5th for loop
sw.WriteLine(sprintf "%s,%.1f,%i" t r s)))

最佳答案

您理解中缺少的部分是 F# 的 Seq惰性。它不会做比需要更多的工作,特别是,除非绝对必要,否则它不会使用序列。特别是,Seq.mapSeq.filter 不像 for 循环;相反,它们就像一个转换管道,在现有转换之上堆叠新的转换。实际上贯穿整个外观的第一段代码是 Seq.sortBy(因为排序序列需要知道它的所有值是什么,所以 Seq.sortBy 必须使用整个序列来完成它的工作)。到那时,Seq.filter 步骤已经发生,CSV 文件中的很多行都被丢弃了,这就是程序消耗的内存少于原始文件总大小的原因。

下面是 Seq 惰性的实际演示,在 F# Interactive 提示符中键入。看这个:

> let s = seq {1..20} ;;
val s : seq<int>

> let t = s |> Seq.map (fun i -> printfn "Starting with %d" i; i) ;;
val t : seq<int>

> let u = t |> Seq.map (fun i -> i*2) ;;
val u : seq<int>

> let v = u |> Seq.map (fun i -> i - 1) ;;
val v : seq<int>

> let w = v |> Seq.filter (fun i -> i > 10) ;;
val w : seq<int>

> let x = w |> Seq.sortBy id ;;
val x : seq<int>

> let y = x |> Seq.iter (fun i -> printfn "Result: %d" i) ;;
Starting with 1
Starting with 2
Starting with 3
Starting with 4
Starting with 5
Starting with 6
Starting with 7
Starting with 8
Starting with 9
Starting with 10
Starting with 11
Starting with 12
Starting with 13
Starting with 14
Starting with 15
Starting with 16
Starting with 17
Starting with 18
Starting with 19
Starting with 20
Result: 11
Result: 13
Result: 15
Result: 17
Result: 19
Result: 21
Result: 23
Result: 25
Result: 27
Result: 29
Result: 31
Result: 33
Result: 35
Result: 37
Result: 39
val y : unit = ()

> let z = w |> Seq.iter (fun i -> printfn "Result: %d" i) ;;
Starting with 1
Starting with 2
Starting with 3
Starting with 4
Starting with 5
Starting with 6
Result: 11
Starting with 7
Result: 13
Starting with 8
Result: 15
Starting with 9
Result: 17
Starting with 10
Result: 19
Starting with 11
Result: 21
Starting with 12
Result: 23
Starting with 13
Result: 25
Starting with 14
Result: 27
Starting with 15
Result: 29
Starting with 16
Result: 31
Starting with 17
Result: 33
Starting with 18
Result: 35
Starting with 19
Result: 37
Starting with 20
Result: 39
val z : unit = ()

请注意,即使 Seq.sortBy 需要使用整个列表才能完成其工作,因为在我创建序列时没有请求 Seq 的任何部分x,它实际上并没有开始遍历这些值。只有使用 Seq.iter 的序列 yz 实际上触发了所有值的运行。 (但是您可以看到,对于 ysortBy 步骤必须在 iter 步骤运行之前完整运行,但是对于 z 没有 sortBy 步骤,每个值一次一个地通过转换管道,只有在每个值都被完全处理后,下一个值才会开始处理).

关于F#管道函数执行流程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55166608/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com