[英]bulk adding to a map, in F#
我有一个简单的类型:
type Token =
{
Symbol: string
Address: string
Decimals: int
}
和一个 memory 缓存(它们在数据库中):
let mutable private tokenCache : Map<string, Token> = Map.empty
令牌模块的一部分。
有时我会以Token array的形式添加一些新条目,并且我想更新缓存。
它很少发生(每百万次读取不到一次)。
当我用新批次更新数据库时,我也想更新缓存 map,我刚刚写了这个:
tokenCache <- tokens |> Seq.fold (fun m i -> m.Add(i.Symbol, i)) tokenCache
由于这种情况很少发生,我并不真正关心性能,所以这个问题是出于好奇:
当我这样做时,map 将在令牌数组中的每个条目重新创建一次:10 个新令牌,10 个 map 重新创建。 我认为这是处理这个问题的最“F#”方式。 这让我想到:将 map 转换为 KVP 列表,获得不同的 output 并重新创建 map 不是更有效吗? 还是有另一种我没有想到的方法?
这不是对所述问题的回答,而是对您在评论中提出的问题的澄清。
你表达的这个前提是不正确的:
map 将在令牌数组中的每个条目重新创建一次
map 实际上并没有为每次插入完全重新创建。 但同时,您在评论中表达的另一个假设也是不正确的:
所以不变性是从语言的角度来看的,编译器不会在幕后重新创建 object?
不变性是真实的。 但是 map 也不会每次都重新创建。 有时确实如此,但并非每次都如此。
我不会准确描述Map
的工作原理,因为这太复杂了。 相反,我将在列表中说明原理。
F# 列表是“单链表”,这意味着每个列表包含两件事:(1)第一个元素(称为“头”)和(2)对 rest 元素(称为“尾”)的引用(指针)。 这里要注意的关键是“其余元素”部分本身也是一个列表。
因此,如果您声明这样的列表:
let x = [1; 2; 3]
它将在 memory 中表示,如下所示:
x -> 1 -> 2 -> 3 -> []
名称x
是对第一个元素的引用,然后每个元素都有对下一个元素的引用,最后一个 - 对空列表的引用。 到目前为止,一切都很好。
现在让我们看看如果向这个列表中添加一个新元素会发生什么:
let y = 42 :: x
现在列表y
将表示如下:
y -> 42 -> 1 -> 2 -> 3 -> []
但这幅画少了一半。 如果我们在比y
更宽的 scope 中查看 memory ,我们会看到:
x -> 1 -> 2 -> 3 -> []
^
|
/
y -> 42
因此,您会看到y
列表包含两件事(就像所有列表一样):第一个元素42
和对元素1->2->3
的 rest 的引用。 但是“其余元素”位不是y
独有的,它有自己的名称x
。
因此,您有两个列表x
和y
,分别是 3 和 4 个元素,但它们一起只占用 memory 的 4 个单元格,而不是 7 个。
还有一点需要注意的是,当我创建y
列表时,我不必从头开始重新创建整个列表,我不必将1
、 2
和3
从x
复制到y
。 这些单元格就在它们所在的位置,而y
只得到了对它们的引用。
第三点要注意的是,这意味着将元素添加到列表中是一个 O(1) 操作。 没有复制所涉及的清单。
第四点(希望是最后的)要注意的是,这种方法只有在不变性的情况下才有可能。 只是因为我知道x
列表永远不会改变,所以我可以参考它。 如果它可能发生变化,我将被迫复制它以防万一。
这种安排,其中数据结构的每次迭代都构建在前一个“之上”,称为“持久数据结构”(嗯,更准确地说,它是一种持久数据结构)。
它的工作方式对于链表很容易看出,但它也适用于更多涉及的数据结构,包括地图(表示为树)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.