所以我有一个问题是如何折叠两个列表来生成一个新列表(或数组,或序列或最快的基本数据类型),因为我使用的是List.Fold和::
运营商建立一个列表,当我意识到我基本上生产了十亿个不可变列表...这似乎比传统的循环更慢,我想知道我在做什么是解决我的“正确”方法F#中的问题......
这是我到目前为止所得到的。我正在尝试构建一个结构为Dictionary<string,Node>*Edge list
的图形,其输入是节点列表和边缘列表。每个节点都有一个插槽用于邻接列表(我不喜欢这些列表,我只是不知道哪种数据类型最好......)边缘(所以我只需要查找一个节点)。我的build_graph正在尝试获取节点列表和边缘列表,并搜索每个节点的所有边缘,并构建一个新的节点列表,其中填充了邻接列表......
所以这里是代码......(试图将它分隔开以使得线条不够长)
let build_graph (nodes:Node<'a> list) (edges:Edge<'a> list) (g:Graph<'a>) =
let nlist = List.fold(fun nlist node
-> let adjlist =
List.fold(fun adj edge
-> if edge.Node1.Name = node.Name or edge.Node2.Name = node.Name
then edge::adj
else adj) [] edges
node.Adjacent = Some(adjlist) |> ignore
node::nlist
) [] nodes
match g with
| Dictionary_Graph(_,_) -> let dict = new Dictionary<string,Node<'a>>()
List.iter(fun node -> dict.Add(node.Name,node)) nlist |> ignore
Dictionary_Graph(dict,edges)
| ConcurrentDictionary_Graph(_,_) -> let dict = new ConcurrentDictionary<string,Node<'a>>()
List.iter(fun node -> dict.AddOrUpdate(node.Name,node,(fun k v -> node)) |> ignore) nlist |> ignore
ConcurrentDictionary_Graph(dict,edges)
这是解决问题的正确方法吗?如果它不正确,有没有更快的方法来做我想在这里做的事情?
答案 0 :(得分:3)
在F#中重复创建新的不可变列表绝对没有错,只要它是通过预先添加来完成的 - 就像你在这里一样。此操作为O(1),因此不应该是性能问题。事实上,列表可能是此类事物的最佳F#集合。
转到那里的代码,有一些问题。首先:
node.Adjacent = Some(adjlist) |> ignore
此行检查node.Adjacent
是否等于Some(adjlist)
,然后忽略该比较的结果。我怀疑你有意:
node.Adjacent <- Some(adjlist)
在折叠中使用可变性可能是一种奇怪的做法,我不会特别推荐。我建议您选择添加新的邻接列表来创建新节点。
示例:
// create new record with adjacency list supplied
{Item = node.Item; Name = node.Name; Adjacent = Some adjlist}
其次,你的第二个List.fold
看起来像是对我的过滤器。你可以替换:
List.fold (fun adj edge ->
if edge.Node1.Name = node.Name or edge.Node2.Name = node.Name then edge::adj
else adj) [] edges
与
edges
|> List.filter (fun edge -> edge.Node1.Name = node.Name || edge.Node2.Name = node.Name)
这不是问题,代码的一部分应该可以使用,但使用过滤器更简单,更简洁。
同样,您的第一个List.fold
可以替换为List.map
。
最终结果可能是:
let buildGraph (nodes:Node<'a> list) (edges:Edge<'a> list) (g:Graph<'a>) =
let nlist =
nodes |> List.map (fun node ->
let adjlist =
edges |> List.filter(fun edge -> edge.Node1.Name = node.Name || edge.Node2.Name = node.Name)
{Item = node.Item; Name = node.Name; Adjacent = Some adjlist})
match g with
| DictionaryGraph(_) ->
let dict = new Dictionary<string,Node<'a>>()
List.iter(fun node -> dict.Add(node.Name,node)) nlist |> ignore
Dictionary_Graph(dict,edges)
| ConcurrentDictionaryGraph(_) ->
let dict = new ConcurrentDictionary<string,Node<'a>>()
List.iter(fun node -> dict.AddOrUpdate(node.Name,node,(fun k v -> node)) |> ignore) nlist |> ignore
ConcurrentDictionaryGraph(dict,edges)