Dictionary 批量添加到地图,单位为F#
我有一个简单的类型:Dictionary 批量添加到地图,单位为F#,dictionary,f#,Dictionary,F#,我有一个简单的类型: type Token = { Symbol: string Address: string Decimals: int } 和内存缓存(它们位于数据库中): 让可变私有令牌缓存:Map=Map.empty 令牌模块的一部分 有时,我会以令牌数组的形式添加一些新条目,并希望更新缓存 这种情况很少发生(每百万次读取不到一次) 当我用新批更新数据库时,我也想更新缓存映射,我刚刚写了以下内容: t
type Token =
{
Symbol: string
Address: string
Decimals: int
}
和内存缓存(它们位于数据库中):
让可变私有令牌缓存:Map=Map.empty
令牌模块的一部分
有时,我会以令牌数组的形式添加一些新条目,并希望更新缓存
这种情况很少发生(每百万次读取不到一次)
当我用新批更新数据库时,我也想更新缓存映射,我刚刚写了以下内容:
tokenCache <- tokens |> Seq.fold (fun m i -> m.Add(i.Symbol, i)) tokenCache
tokenCache Seq.fold(fun m i->m.Add(i.Symbol,i))tokenCache
由于这种情况很少发生,我并不真正关心性能,因此这个问题出于好奇:
当我这样做时,映射将在令牌数组中的每个条目中重新创建一次:10个新令牌,10个映射重新创建。我认为这是处理这件事的最“F”的方式。这让我思考:将映射转换为KVP列表、获取distinct的输出并重新创建映射不是更有效吗?或者还有其他方法我没有考虑过吗?这不是对上述问题的回答,而是对您在评论中提出的问题的澄清。 您所表达的前提是不正确的: 该映射将在令牌数组中的每个条目中重新创建一次 实际上,并不是每次插入都会完全重新创建贴图。但与此同时,你在评论中表达的另一个假设也是不正确的:
所以不变性是从语言的角度来看的,编译器不会在幕后重新创建对象 不变性是真实的。但地图也不是每次都会被重新创建。有时是这样,但不是每次都是这样 我不打算确切地描述
Map
是如何工作的,因为这太复杂了。相反,我将在列表中说明该原理
F#列表是“单链表”,这意味着每个列表由两部分组成:(1)第一个元素(称为“head”)和(2)指向其余元素(称为“tail”)的引用(指针)。这里需要注意的关键是,“元素的其余部分”本身也是一个列表 因此,如果您声明这样的列表:
let x = [1; 2; 3]
x -> 1 -> 2 -> 3 -> []
y -> 42 -> 1 -> 2 -> 3 -> []
它将在内存中表示如下:
let x = [1; 2; 3]
x -> 1 -> 2 -> 3 -> []
y -> 42 -> 1 -> 2 -> 3 -> []
名称x
是对第一个元素的引用,然后每个元素都有对下一个元素的引用,最后一个元素是对空列表的引用。到目前为止还不错
现在,让我们看看如果将新元素添加到此列表中会发生什么:
let y = 42 :: x
现在列表y
将如下所示:
let x = [1; 2; 3]
x -> 1 -> 2 -> 3 -> []
y -> 42 -> 1 -> 2 -> 3 -> []
但是这张照片缺了一半。如果我们将内存放在比y
更广的范围内,我们会看到:
x -> 1 -> 2 -> 3 -> []
^
|
/
y -> 42
因此,您可以看到y
列表由两部分组成(与所有列表一样):第一个元素42
和对其余元素1->2->3
的引用。但是“其余元素”位不是y
所独有的,它有自己的名称x
因此,你有两个列表,分别是3个和4个元素,但它们一起只占用4个内存单元,而不是7个
另外需要注意的是,当我创建y
列表时,我不必从头开始重新创建整个列表,也不必将1
、2
和3
从x
复制到y
。这些单元格保持在原来的位置,y
只获得了对它们的引用
需要注意的第三点是,这意味着在列表中预先添加元素是一个O(1)操作。不复制涉及的列表
第四点(希望也是最后一点)需要注意的是,这种方法之所以可能是因为不变性。只有因为我知道x
列表永远不会改变,我才能引用它。如果有变化,我只是以防万一
这种安排,其中数据结构的每次迭代都是在前一次迭代的基础上构建的,称为“”(更准确地说,它是一种持久数据结构)
它的工作方式对于链表来说很容易看到,但对于更复杂的数据结构也很有效,包括映射(以树的形式表示)。映射并不是为每个元素都完全重新创建的。因此,从语言的角度来看,不可变性是,编译器不会在幕后重新创建对象?不,这也不正确。我将尝试发布一个答案。我理解这个想法(我来自asm/c背景),我假设列表是不可变的对象,例如指向节点的指针数组(如果添加到头部,则需要复制该数组,如果添加到末端,则可能需要扩展该数组)。所以我猜每个节点都有一个refcount和下一个字段,对吗?不,refcount是古老的,我认为除了STL之外,没有人再使用它们了。NET使用a来处理未引用的对象。好的,我明白了,所以它遍历对象图以查看哪些对象仍然处于活动状态;我记得几年前读过。很好,谢谢你的澄清。