【问题标题】:F# - Flatten List/RangeF# - 展平列表/范围
【发布时间】:2011-04-30 00:52:11
【问题描述】:

我是 F# 的新手,想知道如何将列表展平。

基本上,我在数据库中存储了一条具有 min_age 和 max_age 范围的记录(为简洁起见,这是一个虚构的示例 - 我不是 agist!)。我的字段如下所示:

身份证, 成本, 储蓄, min_age, 最大年龄

我基本上有一个 F# 类,它充当与此表的一对一映射 - 即所有属性都精确映射到数据库字段。

我想要做的是压平这个范围。所以,而不是包含这样的项目的列表:

saving_id = 1, cost = 100, savings = 20, min_age = 20, max_age = 26
saving_id = 2, cost = 110, savings = 10, min_age = 27, max_age = 31

我想要一个包含以下项目的列表:

saving_id = 1, cost = 100, savings = 20, age = 20
saving_id = 1, cost = 100, savings = 20, age = 21
etc.
saving_id = 2, cost = 110, savings = 10, age = 27
saving_id = 2, cost = 110, savings = 10, age = 28
etc.

是否有任何内置机制以这种方式展平列表和/或有人知道如何实现这一点? 提前致谢,

日本

【问题讨论】:

    标签: f# flatten


    【解决方案1】:

    您可能想要使用 Seq.collect。它将序列连接在一起,因此在您的情况下,您可以在输入上映射一个函数,将单个年龄范围记录拆分为一系列年龄记录,并使用 Seq.collect 将它们粘合在一起。

    例如:

    type myRecord =
    { saving_id: int;
      cost: int;
      savings: int;
      min_age: int;
      max_age: int }
    
    type resultRecord =
        { saving_id: int;
          cost: int;
          savings: int;
          age: int }
    
    let records = 
        [ { saving_id = 1; cost = 100; savings = 20; min_age = 20; max_age = 26 }
          { saving_id = 2; cost = 110; savings = 10; min_age = 27; max_age = 31 } ]
    
    let splitRecord (r:myRecord) =
        seq { for ageCounter in r.min_age .. r.max_age -> 
                { saving_id = r.saving_id;
                  cost = r.cost;
                  savings = r.savings;
                  age = ageCounter }
        }
    
    let ageRanges = records |> Seq.collect splitRecord
    

    编辑:您还可以使用带有 yield 的序列生成器!

    let thisAlsoWorks = 
        seq { for r in records do yield! splitRecord r }  
    

    【讨论】:

    • 不错的答案。我猜 OP 在哪里要求“内置机制”,该机制只有在不涉及任何自定义记录类型的情况下才会真正起作用,但事实上,这个解决方案看起来很优雅。
    • 序列表达式可以是一个通用的优雅单行:let flatten seqOfSeq = seq { for seq in seqOfSeq do yield! seq}
    【解决方案2】:

    同意 cfern 的回答,但想知道这是否会从使用另一个“内置”函数中受益。这是splitRecord 函数的另一个版本,它显示了用于展开序列的库调用。除了为Seq.unfold 提供示例之外,这里没有任何收获。

    let splitRecord (r:myRecord) = 
        Seq.unfold (fun curr_age ->
                        if curr_age <= r.max_age then
                            Some({  saving_id = r.saving_id; 
                                    cost = r.cost; 
                                    savings = r.savings; 
                                    age = curr_age } ,
                                    curr_age + 1) 
                        else None)
                    r.min_age
    

    【讨论】:

    • 有趣的解决方案 :) 当然我发现在几乎所有情况下,while whatever do yield value 几乎总是比 Seq.unfold 更具可读性 :)
    • @Juliet 我发现尝试在任何地方查看库函数的案例有助于在它们变得有用时记住它们。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多