Map.ofSeq具有重复键的行为是什么?

sdg*_*sdh 5 f#

Map.ofSeq当同一个键出现两次时的行为是什么?

文档没有提到这种情况.

Aar*_*ach 8

让我们凭经验测试一下,找出......

这个例子:

[("key", 1); ("key", 2); ("key", 3)] |> Map.ofSeq
Run Code Online (Sandbox Code Playgroud)

产生以下结果:

map [("key", 3)]
Run Code Online (Sandbox Code Playgroud)

这个例子:

[("key", 3); ("key", 1);] |> Map.ofSeq
Run Code Online (Sandbox Code Playgroud)

给出这个结果:

map [("key", 1)]
Run Code Online (Sandbox Code Playgroud)

因此,Map.ofSeq当存在重复时,似乎使用给定键的序列中的最后一个条目.

编辑

正如Fyodor Soikin指出的那样,您不会希望依赖代码中的未记录行为.因此,如果要在序列中存在多个具有相同键的值时确保选择给定值的特定行为,则可以使用如下函数:

module Map =
    let ofSeqWithDuplicates<'key,'value when 'key : comparison> (resolver: 'key -> 'value seq -> 'value) seq =
        let rec getDuplicates state remaining = 
            match remaining |> Seq.tryHead with
            | Some (key, value) -> 
                let newItem = Seq.singleton value
                let newState =                     
                    match state |> Map.tryFind key with
                    | Some existing -> state |> Map.add key (existing |> Seq.append newItem)
                    | None -> state |> Map.add key newItem
                remaining |> Seq.tail |> getDuplicates newState
            | None -> state

        seq
        |> getDuplicates Map.empty<'key, 'value seq>
        |> Map.map (fun key values -> values |> resolver key)
Run Code Online (Sandbox Code Playgroud)

这允许您传递一个名为的函数resolver,该函数从给定键的重复值列表中选择值.当我们使用上面的第一个例子时,我们可以明确地选择最小值,如下所示:

[("key", 1); ("key", 2); ("key", 3)] 
|> Map.ofSeqWithDuplicates (fun key values -> values |> Seq.min)
Run Code Online (Sandbox Code Playgroud)

所以现在我们得到地图:

map [("key", 1)]
Run Code Online (Sandbox Code Playgroud)


Fyo*_*kin 7

源代码表示的结构Map从序列经由的多个调用来实现add,在源集合的顺序来执行,因此导致的"最后的写入胜"的语义.

但是,由于文档没有提到此属性,因此在生产代码中依赖它是不明智的.目前,此行为是内部实现细节,可能会在标准库的后续版本中发生更改.

  • 在实践中,如果你有一个 API,你怀疑如果你改变了未记录的行为,它会让许多用户不高兴,我会尽力保留这种行为。也许打开一个 PR 并进行文档更改以将其记录下来? (2认同)