f# - 字典列表与字典序列
问题描述
在此示例中,我无法理解 F# 的 List 和 Seq 之间的区别。我认为主要区别在于 Seq 有点懒惰,但我一定遗漏了一些东西。
此代码片段:
open System.Collections.Generic
let arr =
["a"; "b"; "c"]
|> Seq.map (fun a -> let dic = Dictionary () in dic.Add("key", a); dic) in
arr
|> Seq.iter (fun a ->
printfn "here";
a.["key"] <- "something"
);
arr
|> Seq.iter (fun a -> printfn "%s" a.["key"])
给
here
here
here
a
b
c
鉴于(将第一个 Seq 替换为 List)
open System.Collections.Generic
let arr =
["a"; "b"; "c"]
|> List.map (fun a -> let dic = Dictionary () in dic.Add("key", a); dic) in
arr
|> Seq.iter (fun a ->
a.["key"] <- "something"
);
arr
|> Seq.iter (fun a -> printfn "%s" a.["key"])
给
something
something
something
为什么我使用 Seq 时 Dictionary 的值不会改变?here
打印时清楚地访问了元素。
提前致谢。
解决方案
正如您所说,原因恰恰Seq
是“有点懒惰”。
从某种意义上说,它是“懒惰的”,每次您要求它时都会对其进行评估。所有的。直到最后一个非懒惰的事情。
特别是,调用Seq.map
是惰性的。它不会在内存中创建一个充满字典的新结构。相反,它创建了一些你可以称之为“管道”的东西。这个管道从你的列表开始["a"; "b"; "c"]
,然后有一个指令:每次有人试图迭代这个序列时,为每个元素创建一个新字典。“每次”位在那里很重要 - 因为您要迭代序列两次(一次打印“这里”,另一次打印值),字典也被创建两次。您将“某物”推送到其中的字典和您从中获取“密钥”的字典不是同一个字典。
为了进一步说明,试试这个:
let s = ["a";"b";"c"] |> Seq.map( fun x -> printfn "got %s" x; x )
s |> Seq.iter(printfn "here's %s")
s |> Seq.iter(printfn "again %s")
这将打印以下内容:
got a
here's a
got b
here's b
got c
here's c
got a
again a
got b
again b
got c
again c
看看每个元素的“got”输出如何发生两次?那是因为Seq.map
每次迭代都有效,而不仅仅是一次。
列表不是这样。每次你List.map
,你都会在内存中创建一个全新的列表。它只是永远坐在那里(“永远”被定义为“直到垃圾收集器到达它”)并等待你用它做某事。如果你用它做多件事,它仍然是同一个列表,它不会被重新创建。这就是为什么您的字典始终是相同的字典,它们不会像Seq
. 这就是为什么您可以修改它们并在下次查看时看到修改。
您可以借助Seq.cache
. 此函数采用常规的按需评估序列并返回一个相同的序列,除了每个元素只被评估一次。
但与列表不同的是,它不会在调用它的那一刻Seq.cache
评估整个序列。相反,它将创建一个可变缓存,每次评估时都会更新。
这对于序列非常大甚至无限的情况很有用,但您只需要在它的开头使用少量有限数量的元素。
插图:
let s = ["a";"b";"c"]
|> Seq.map( fun x -> printfn "got %s" x; x )
|> Seq.cache
s |> Seq.iter(printfn "here's %s")
s |> Seq.iter(printfn "again %s")
输出:
got a
here's a
got b
here's b
got c
here's c
again a
again b
again c
推荐阅读
- spring-boot - 如何确保我的反应式应用程序以事件循环样式运行
- php - Laravel 5.6 正则表达式验证总是显示错误
- c# - 数据类型转换
- scala - foldLeft 如何在 (0 /: (1 to 6))(_+_) 中求值?
- paperjs - 悬停paperjs项目时显示指针光标
- javascript - Ancor 引用 javascript
- ruby-on-rails - 如何在 ruby on rails 中使用 select_tag 返回多个参数
- mips - 在 MIPS 中使用 $0 作为目的地的目的是什么
- c# - 手动登录后如何使 Chrome Headless
- ruby-on-rails-4 - PG::ConnectionBad:将 rails 从 4.2 升级到 5.2 后连接关闭