【问题标题】:Adding elements to a Map in F# using a for loop使用 for 循环将元素添加到 F# 中的 Map
【发布时间】:2025-11-26 02:45:02
【问题描述】:

代码:

let studentMap =
    for i = 0 to count do
        Map.empty.Add(students.[i].getId(), students.[i].getScores())

我正在尝试按顺序添加到地图中。我在一个数组中有学生对象,并试图按顺序添加它们。我对如何做到这一点感到困惑。我想也许你制作了一个空地图,然后通过 for 循环按顺序添加到它,但它总是会造成麻烦并且不起作用。有没有办法使用 for 循环将项目添加到地图中? <key/value> 对是这样的:<string, int array>。这就是我希望它格式化的方式,但它一直给我带来麻烦。我将再次重申目标以澄清:我希望能够使用 for 循环将项目添加到地图中,并使用我的学生对象数组来获取我需要的适当数据。例如,我将能够给它一个字符串并取回该学生的成绩。我知道我正在处理一个奇怪的问题,但我首先需要尝试一些简单的事情。

【问题讨论】:

    标签: loops for-loop map f# add


    【解决方案1】:

    您可以使用可变映射变量:

    let studentMap = 
        let mutable m <- Map.empty  
        for i = 0 to count do  
            m <- m.Add(students.[i].getId(), students.[i].getScores())
        m
    

    或可变字典:

    let studentMap = 
        let m = new System.Collections.Generic.Dictionary<int, Scores>()  
        for i = 0 to count do  
            m.Add(students.[i].getId(), students.[i].getScores())
        m
    

    更实用的解决方案是使用折叠:

    let studentMap = seq { 0 .. count } |> Seq.fold (fun (m: Map<int, Scores>) i -> m.Add(students.[i].getId(), students.[i].getScores())) Map.empty
    

    【讨论】:

    • 是的,我不知道为什么我不使用可变的大声笑。虽然在第二部分我不得不改用 let mutable m = Map.empty。
    【解决方案2】:

    您可以尝试更实用的惯用方法:

    假设您有一个Student 类型的数组(在下面的示例中是一个空数组):

    let students = Array.empty<Student>
    

    您可以将数组转换为Map

    let mapStudents = students 
                        |> Array.map (fun s -> (s.getId(), s.getScore()))
                        |> Map.ofArray
    

    【讨论】:

    • 似乎它仍然给我带来了问题,但无论如何我都会对函数式编程进行更多研究,以便我可以开始更多地理解这一点。但我会保存它并尝试让它工作。
    • 您有什么问题?
    【解决方案3】:

    我认为 Map.ofArray 方法可能是最好的,但值得指出的是,for 循环可以做得更好:

    let map = new System.Collections.Generic.Dictionary<int, Scores>()
    for student in students do
       map.Add(student.getId(), student.getScore())
    

    这巧妙地避免了数组边界错误。

    【讨论】:

    • 这里有Map不可变的问题。您需要重新分配从Add返回的变量
    • 我已经添加了地图的类以澄清
    【解决方案4】:

    在函数式语言中,内置的数据结构是不可变的,也就是说,当你添加一个元素时,会返回一个数据结构的新值。

    如果您想将一种结构转换为另一种结构,您通常可以使用其中一个内置函数,例如Map.ofArray。如果您有更复杂的场景,例如生成值的函数,则可以使用 'loop',并且循环的每次迭代都会返回数据结构的新值。以函数方式表达这种“循环”的方法是使用递归函数

    let studentMap =
        let rec loop currentMap i =
            if i >= count then currentMap
            else
                let newMap = Map.add (students.[i].getId()) (students.[i].getScores()) currentMap
                loop newMap (i+1)
        loop Map.empty 0
    

    现在,您在生成值的方式上拥有了完全的灵活性(它们不必是数组的一部分),并且您避免了在函数式编程中不惯用的可变变量。理想情况下,就像在这种情况下,函数应该是 tail-recursive 以允许尾调用优化(并避免大输入的堆栈溢出)。

    【讨论】: