【问题标题】:Guid generation in F# sequencesF# 序列中的 Guid 生成
【发布时间】:2015-05-05 14:57:45
【问题描述】:

我有以下代码:

open System
open System.Linq

type Child = {
    id: Guid
    name: int
    parent: Guid
}

type Parent = {
    id: Guid
    name: int
    children: seq<Guid>
}

let makeChild name parentId =
    {
        Child.id = Guid.NewGuid()
        name = name
        parent = parentId
    }

let makeParent (group: IGrouping<int, int>) =
    let id = Guid.NewGuid()
    let children = group |> Seq.map (fun x -> makeChild x id)
    let ids = children |> Seq.map (fun x -> x.id)
    ({
        Parent.id = id
        name = group.Key
        children = ids
    }, children)

let makeAll (groups: seq<IGrouping<int, int>>) =
    let result = groups |> Seq.map (fun x -> makeParent x)
    let children = result |> Seq.map (fun x -> snd x) |> Seq.concat
    let parents = result |> Seq.map (fun x -> fst x)
    (parents, children)

(我接受IGrouping&lt;int, int&gt; 而不是seq&lt;int * seq&lt;int&gt;&gt;,因为此代码需要与C# 互操作。)

但是,当我运行以下内容时:

let parents, children = makeAll(Enumerable.Range(0, 100).GroupBy(fun x -> x % 10))

那么没有任何孩子。[i].parent guids 与父母相关。[j].children.[k] i、j、k 的 guid。

为什么不是这样?我怎样才能做到这一点?

【问题讨论】:

    标签: f#


    【解决方案1】:

    没有对此进行测试,但问题似乎在于您将结果 seq 枚举了两次,一次在 let children 中,一次在 let parents 行中。而且由于 guid 生成具有副作用,因此每次枚举都会得到两个不同的结果。

    如果您将 seq 缓存在 let result 行中(或通过将其转换为同一行中的数组或列表来实现它),您应该会得到您要查找的内容:

    let result = groups |> Seq.map (fun x -> makeParent x) |> Seq.cache
    

    makeParent 函数也是如此。 ids seq 也需要缓存。

    像这样的“陷阱”是我发现在函数或接口的边界上使用具体集合类型而不是序列的原因。如果你正在寻找惰性,你可以使用 Lazy 类型使其显式化。

    【讨论】:

    • 从技术上讲,let children 行不做任何枚举。但是,ids 序列在枚举时将重新生成所有具有与枚举children 序列时产生的不同 id 的子代。你说得对。
    • @JoelMueller:是的,我关注的是makeAll 代码,而您说的是makeParent 代码。事实上,这也需要缓存。
    猜你喜欢
    • 2015-08-19
    • 1970-01-01
    • 2011-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-26
    • 2010-12-04
    相关资源
    最近更新 更多