2015-05-05 2 views
1

У меня есть следующий код:поколение Guid в F # последовательностей

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<int, int> вместо seq<int * seq<int>> потому что этот код должен взаимодействовать с C#)

Однако, когда я бегу со следующим :.

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

тогда ни один из детей [я] .parent Идентификаторы GUID коррелируют с родителями [J] .children [K] для GUID, I, J, K...

Почему это не так? Как я могу это сделать?

ответ

3

Не испытал это, но проблема в том, что вы перечисляете результат seq дважды, один раз в let children, один раз в строке let parents. И так как генерация инициатора является побочной, вы получаете два разных результата для каждой из перечислений.

Если вы кэшировать с послед в let result линии (или материализовать его, превращая его в массив или список в той же строке), вы должны получить то, что вы ищете:

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

то же самое в функции makeParent. Сегмент ids необходимо также кэшировать.

«Ловушки» вот почему я считаю предпочтительным использовать типы бетонных коллекций, а не seqs на границах функций или интерфейсов. И если вы ищете лень, вы можете сделать это явным, используя тип Lazy.

+0

Технически строка 'let children' не делает никаких перечислений. Тем не менее, последовательность 'ids', при перечислении, будет регенерировать всех детей с разными идентификаторами, чем те, которые производятся после перечисления последовательности« children ». Вы правы в отношении исправления. –

+0

@JoelMueller: Верно, я сосредоточился на коде 'makeAll', и вы говорите о коде' makeParent'. На самом деле это нужно также кэшировать. – scrwtp

Смежные вопросы