F# 词典列表';s vs字典序列';s
在这个例子中,我很难理解F#的列表和Seq之间的区别。我认为主要的区别是Seq有点懒,但我肯定错过了什么 此代码段:F# 词典列表';s vs字典序列';s,f#,F#,在这个例子中,我很难理解F#的列表和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 "her
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"])
鉴于(将第一个序号替换为列表)
为什么我使用Seq时字典值不改变?打印此处的
时,可以清楚地访问元素
提前谢谢。原因正是你所说的
Seq
有点懒
它是“懒惰”的,因为每次你要求它时,它都会被评估。所有这些。直到最后一件非懒惰的事情
特别是,对Seq.map
的调用是惰性的。它不会在内存中创建一个充满字典的新结构。相反,它创建了一些你可以称之为“管道”的东西。这个管道从您的列表开始,然后有一条指令:每当有人试图迭代这个序列时,为每个元素创建一个新的字典。“everytime”位在这里很重要-因为您在序列上迭代了两次(一次打印“here”,另一次打印值),所以字典也会被创建两次。将“某物”推入的字典和从中获取“键”的字典不是同一个字典
为了进一步说明,请尝试以下方法:
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
查看如何为每个元素生成两次“get”输出?这是因为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
我在两个示例中都添加了一些
printfn
s,这样您就可以看到它们的区别:
let arr =
["a"; "b"; "c"]
|> Seq.map (fun a -> printfn "seq: %s" a
let dic = Dictionary ()
dic.Add("key", a)
dic)
arr
|> Seq.iter (fun a ->
printfn "here seq"
a.["key"] <- "something"
)
arr
|> Seq.iter (fun a -> printfn "%s" a.["key"])
而这个,
let arr =
["a"; "b"; "c"]
|> List.map (fun a -> printfn "list: %s" a
let dic = Dictionary ()
dic.Add("key", a)
dic)
arr
|> Seq.iter (fun a ->
printfn "here list";
a.["key"] <- "something"
)
arr
|> Seq.iter (fun a -> printfn "%s" a.["key"])
正如你所看到的,行为是完全不同的
Seq.map
是惰性的,这意味着它仍然是一个函数,只有在严格必要时才能被调用。每次调用它时,它都会从一开始就根据需要映射每个元素Seq.map
被调用两次,每个Seq.iter
调用一次,每次它为每个元素创建一个新的字典,然后被垃圾收集器丢弃
另一方面,List.map
只被调用一次,它只在整个输入列表中创建一个新的字典列表一次
got a
here's a
got b
here's b
got c
here's c
again a
again b
again c
let arr =
["a"; "b"; "c"]
|> Seq.map (fun a -> printfn "seq: %s" a
let dic = Dictionary ()
dic.Add("key", a)
dic)
arr
|> Seq.iter (fun a ->
printfn "here seq"
a.["key"] <- "something"
)
arr
|> Seq.iter (fun a -> printfn "%s" a.["key"])
seq: a
here seq
seq: b
here seq
seq: c
here seq
seq: a
a
seq: b
b
seq: c
c
let arr =
["a"; "b"; "c"]
|> List.map (fun a -> printfn "list: %s" a
let dic = Dictionary ()
dic.Add("key", a)
dic)
arr
|> Seq.iter (fun a ->
printfn "here list";
a.["key"] <- "something"
)
arr
|> Seq.iter (fun a -> printfn "%s" a.["key"])
list: a
list: b
list: c
here list
here list
here list
something
something
something