【问题标题】:F# System.InvalidOperationException: Collection was modified; enumeration operation may not executeF# System.InvalidOperationException:集合已修改;枚举操作可能无法执行
【发布时间】:2016-04-22 02:40:23
【问题描述】:

我在 F# 中遇到了这个问题 [不是 C#,那里已经有类似的帖子有类似的答案]

我了解在 for 循环中枚举字典时无法修改字典 我应该如何解决这个问题?

let edgelist1 = [(1,2,3.0f);(1,2,4.0f);(5,6,7.0f);(5,6,8.0f)]
let dict_edges = new Dictionary<int*int,(int*int*float32) list>()
for x in edgelist1 do dict_edges.Add ((fun (a,b,c)-> (a,b)) x, x)
for k in dict_edges.Keys do dict_edges.[k] <- (dict_edges.[k] |> List.rev)

System.InvalidOperationException:集合已修改;枚举 操作可能无法执行。

在 System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource 资源)在 System.Collections.Generic.Dictionary`2.KeyCollection.Enumerator.MoveNext() 在 .$FSI_0101.main@()

个人认为这是有效的

dict_edges.[(1,2)] <- dict_edges.[(1,2)] |> List.rev;;

在 for 循环中,我只需要更改字典值,而不是键。

谢谢

【问题讨论】:

标签: list dictionary f#


【解决方案1】:

您可以将所有键复制到一个临时列表中,然后在修改原始字典的同时迭代该列表:

for k in (dict_edges.Keys |> Seq.toList) do 
   dict_edges.[k] <- (dict_edges.[k] |> List.rev)

但我强烈建议您重新考虑您的方法并摆脱就地突变。您现在面临的这个小问题只是对基于突变的程序可能出错的第一次尝试。

【讨论】:

    【解决方案2】:

    您发布的代码甚至在语法上都不正确,因此不清楚您究竟想要实现什么(编译器在((fun (a,b,c)-&gt; (a,b)) x, x) 尖叫说它希望第二个x 成为一个列表)

    我猜你想要的是:你有一个加权边列表,其中节点之间可以有多个边。您希望将它们折叠成规范形式,在其中您将所有连接任何节点对(i,j) 的边分组。只需使用任何groupBy 库函数,就可以了:

    let map_edges =
        edgelist1
        |> List.groupBy (fun (a, b, _) -> (a, b))
        |> Map.ofList
    

    在当前代码中,您使用((fun (a,b,c)-&gt; (a,b)) x, x) 来提取元组的成员。相反,在for 表达式中使用模式:

    for (a, b, c) in edgelist1 do dict_edges.Add ((a, b), [(a, b, c)])
    

    (我添加了[] 以使其至少可以编译)

    还请注意,您正在复制信息:您将节点元组存储在列表的键和值中,从而使数据结构可能不一致且更大。考虑以下几点:

    let map_edges =
        edgelist1
        |> List.map (fun (a, b, c) -> (a, b), c)
        |> List.groupBy fst
        |> List.map (fun (nodeTuple, edgeList) -> 
            nodeTuple, (edgeList |> List.map snd))
        |> Map.ofList
    
    
    map_edges
    |> Map.iter (fun (nodeI, nodeJ) edgeList ->
        edgeList
        |> Seq.map string
        |> String.concat "; "
        |> printfn "Nodes (%i, %i): weights %s" nodeI nodeJ
    )
    

    (您可能希望使用序列作为中间表示而不是列表)

    【讨论】:

    • 感谢我不知道 List.groupby,我自己重写了这个函数!
    【解决方案3】:

    直接说dict_edges = dict_edges.map($0.reverse())不是更简单吗

    抱歉 f# 语法不好

    【讨论】:

      猜你喜欢
      • 2020-02-07
      • 2022-06-17
      • 2011-10-05
      • 2015-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多