Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Function 可以在f中编写这样的递归分组函数吗#_Function_Recursion_Types_F# - Fatal编程技术网

Function 可以在f中编写这样的递归分组函数吗#

Function 可以在f中编写这样的递归分组函数吗#,function,recursion,types,f#,Function,Recursion,Types,F#,假设您需要将序列分组为元组序列。每个元组都是一个键*seq。所以在某种意义上,结果是一系列的序列 到目前为止,一切都相当标准 如果您想通过其他键对每个子序列进行进一步分组,该怎么办?将另一个groupby函数映射到序列序列的每个元素上是很容易的。然后你会有一系列的序列 开始有点毛茸茸的 如果你想把它进一步分组呢 是否可以编写一个函数,该函数可以接受一个键生成函数和任意序列,然后递归地展开层,然后使用键函数添加另一层分组 我怀疑答案是否定的,因为递归函数没有定义良好的类型 我的尝试是为了进一步说明

假设您需要将序列分组为元组序列。每个元组都是一个键*seq。所以在某种意义上,结果是一系列的序列

到目前为止,一切都相当标准

如果您想通过其他键对每个子序列进行进一步分组,该怎么办?将另一个groupby函数映射到序列序列的每个元素上是很容易的。然后你会有一系列的序列

开始有点毛茸茸的

如果你想把它进一步分组呢

是否可以编写一个函数,该函数可以接受一个键生成函数和任意序列,然后递归地展开层,然后使用键函数添加另一层分组

我怀疑答案是否定的,因为递归函数没有定义良好的类型

我的尝试是为了进一步说明这一观点:

let rec recursiveGrouper keyFunction aSeq =
            let first = Seq.head aSeq
            match first with
                | ((a:'a), _) -> Seq.map (fun (b,(c:seq<'c>)) -> (b, recursiveGrouper keyFunction c)) aSeq
                | _ -> Seq.groupBy keyFunction aSeq
假设我们有一系列的水果记录。我们想按水果的种类对它们进行分类

一种方法是说

let group1 = fruitRecs |> Seq.groupBy key1
使用我们的递归函数,这将是

let group1 = recursiveGrouper key1 fruitRecs
接下来,假设我们希望按源场将group1组中的每个项分组

我们可以说

let group2 =
    group1
    |> Seq.map (fun (f, s) -> (f, Seq.groupBy key2 s))
使用我们的递归函数

let group2 = recursiveGrouper key2 group1
我们可以更进一步,按年级分组,说

let group3 = recursiveGrouper key3 group2

我不认为您可以将其编写为一个递归函数,并对自己施加某种约束,即:


  • tuple
    'key*seq实际上有一些方法可以使用静态约束使递归函数工作。下面是一个小例子:

    // If using F# lower than 4.0, use this definition of groupBy
    module List =
        let groupBy a b = Seq.groupBy a (List.toSeq b) |> Seq.map (fun (a, b) -> a, Seq.toList b) |> Seq.toList
    
    type A = class end // Dummy type
    type B = class end // Dummy type
    type C =
        inherit B    
        static member        ($) (_:C, _:A ) = fun keyFunction -> ()  // Dummy overload
        static member        ($) (_:C, _:B ) = fun keyFunction -> ()  // Dummy overload
        static member        ($) (_:B, aSeq) = fun keyFunction -> List.groupBy keyFunction aSeq // Ground case overload
        static member inline ($) (_:C, aSeq) = fun keyFunction -> List.map (fun (b, c) -> b, (Unchecked.defaultof<C> $ c) keyFunction) aSeq    
    
    let inline recursiveGrouper keyFunction aSeq = (Unchecked.defaultof<C> $ aSeq) keyFunction
    
    // Test code
    type FruitRecord = {Fruit:string; Number:int; SourceFarm:string; Grade:float}
    
    let key1 fr = fr.Fruit
    
    let key2 fr = fr.SourceFarm
    
    let key3 fr =
        match fr.Grade with
        |f when f > 5.0 -> "Very Good"
        |f when f > 2.5 -> "Not bad"
        |_ -> "Garbage"
    
    let fruitRecs = [
        {Fruit = "apple" ; Number = 8; SourceFarm = "F"; Grade = 5.5}
        {Fruit = "apple" ; Number = 5; SourceFarm = "F"; Grade = 4.5}
        {Fruit = "orange"; Number = 8; SourceFarm = "F"; Grade = 5.5}
        ]
    
    let group1 = recursiveGrouper key1 fruitRecs
    let group2 = recursiveGrouper key2 group1
    let group3 = recursiveGrouper key3 group2
    
    //如果使用F#低于4.0,请使用此groupBy定义
    模块列表=
    让groupBy a b=Seq.groupBy a(List.toSeq b)|>Seq.map(fun(a,b)->a,Seq.toList b)|>Seq.toList
    类型A=类结束//虚拟类型
    类型B=类结束//虚拟类型
    C型=
    继承B
    静态成员($)(:C,:A)=fun-keyFunction->()//虚拟重载
    静态成员($)(:C,:B)=fun-keyFunction->()//虚拟重载
    静态成员($)(:B,aSeq)=fun-keyFunction->List.groupBy-keyFunction-aSeq//Ground-case-重载
    静态成员内联($)(:C,aSeq)=fun-keyFunction->List.map(fun(b,C)->b,(Unchecked.defaultof$C)keyFunction)aSeq
    让内联递归Grouper键函数aSeq=(Unchecked.defaultof$aSeq)键函数
    //测试代码
    类型FruitRecord={Fruit:string;Number:int;SourceFarm:string;Grade:float}
    设键1 fr=fr.果
    设key2 fr=fr.SourceFarm
    让键3 fr=
    将fr等级与
    |f当f>5.0时->非常好
    |f当f>2.5->“不错”
    |_->“垃圾”
    let fructRecs=[
    {Fruit=“apple”Number=8;SourceFarm=“F”Grade=5.5}
    {Fruit=“apple”Number=5;SourceFarm=“F”Grade=4.5}
    {Fruit=“orange”Number=8;SourceFarm=“F”Grade=5.5}
    ]
    设group1=recursiveGrouper键1
    设group2=recursiveGrouper键2 group1
    设group3=recursiveGrouper键3 group2
    
    你能从给定的输入中添加至少两个预期输出的示例吗?如果你真的不想
    recursiveGrouper
    是递归的,那么请检查我的答案的编辑。我认为可能会用静态约束来破解某些东西。我可以试一试。@Gustavo:当然,那会很有趣的。那是我通常不会穿过的河流。但是,您应该检查对问题的编辑;)完成,看看河的另一边有什么;)@古斯塔沃:是的,另一边仍然很可怕。我不想维护这样的代码。我承认这是一个有趣的技术,你的工具箱里有。是的,这是一个很大的尺寸:)但我同意你的观点,特别是对于这个特定的函数。我喜欢使用这些技巧来达到一个非常高的通用性水平,但这里不是这样。这在我的机器上似乎不起作用。我认为List.groupBy需要更改为Seq.groupBy,即使这样,我在递归Grouper的第二个应用程序中也会出现一个错误:“水果记录”类型与“string*Seq”类型不匹配是的,我使用了List而不是Seq。如果你愿意,我可以把它改成seqs。但我发布的代码应该对您有用,不是吗?对我来说,列表中没有groupBy。但我使用的是f#3.1,也许f#4上的情况有所不同?@ChechyLevas是的,它附带f#4.0,但您可以添加它。看更新。你已经做了,所以我接受你的答案,尽管我不明白你是怎么做的!
    module Seq = 
        let andGroupBy (projection: 't -> 'newKey) (source: seq<'oldKey * seq<'t>>) = 
            seq { 
                for key, sub in source do
                    let grouped = Seq.groupBy projection sub
                    for nkey, sub in grouped do 
                        yield (key, nkey), sub
            }
    
    values 
    |> Seq.groupBy key1
    |> Seq.andGroupBy key2
    |> Seq.andGroupBy key3
    
    // If using F# lower than 4.0, use this definition of groupBy
    module List =
        let groupBy a b = Seq.groupBy a (List.toSeq b) |> Seq.map (fun (a, b) -> a, Seq.toList b) |> Seq.toList
    
    type A = class end // Dummy type
    type B = class end // Dummy type
    type C =
        inherit B    
        static member        ($) (_:C, _:A ) = fun keyFunction -> ()  // Dummy overload
        static member        ($) (_:C, _:B ) = fun keyFunction -> ()  // Dummy overload
        static member        ($) (_:B, aSeq) = fun keyFunction -> List.groupBy keyFunction aSeq // Ground case overload
        static member inline ($) (_:C, aSeq) = fun keyFunction -> List.map (fun (b, c) -> b, (Unchecked.defaultof<C> $ c) keyFunction) aSeq    
    
    let inline recursiveGrouper keyFunction aSeq = (Unchecked.defaultof<C> $ aSeq) keyFunction
    
    // Test code
    type FruitRecord = {Fruit:string; Number:int; SourceFarm:string; Grade:float}
    
    let key1 fr = fr.Fruit
    
    let key2 fr = fr.SourceFarm
    
    let key3 fr =
        match fr.Grade with
        |f when f > 5.0 -> "Very Good"
        |f when f > 2.5 -> "Not bad"
        |_ -> "Garbage"
    
    let fruitRecs = [
        {Fruit = "apple" ; Number = 8; SourceFarm = "F"; Grade = 5.5}
        {Fruit = "apple" ; Number = 5; SourceFarm = "F"; Grade = 4.5}
        {Fruit = "orange"; Number = 8; SourceFarm = "F"; Grade = 5.5}
        ]
    
    let group1 = recursiveGrouper key1 fruitRecs
    let group2 = recursiveGrouper key2 group1
    let group3 = recursiveGrouper key3 group2