function - 是否可以在 f# 中编写这样的递归分组函数

标签 function recursion types f#

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

到目前为止,一切都很标准。

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

开始有点毛。

如果你想进一步分组呢?

是否有可能编写一个函数,可以接收 key 生成函数和任意序列,并递归地解包层,然后使用 keyFunction 添加另一层分组?

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

我对此的尝试,以进一步说明这个想法:

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

编辑:

让我们添加一个例子来说明它是如何工作的,这是可能的

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 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

最佳答案

实际上有一些方法可以使递归函数工作,使用静态约束。这是一个小例子:

// 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

关于function - 是否可以在 f# 中编写这样的递归分组函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42221584/

相关文章:

c++ - 自上而下的动态编程 VS 递归朴素解决方案。检查运行时执行

c# - 斐波那契数的数据类型

c - 如何在函数内部进行 malloc 并在 C 中返回指针?

c++ - 按矩阵类型转换矩阵乘法,C++

java - 递归运行速度非常慢 - AsyncTask

c - 错误 : ‘str’ undeclared (first use in this function) b = bst_inorder(b->left, str);

javascript - 在 Typescript 中封装 WebSocket 消息

c++ - 解决困难的不完整类型错误

python - 将函数作为参数传递

linux - 程序是否进行系统调用以获取 linux 中环境变量的值?