4

I'm new to F# and am wondering how I would go about flattening a list.

Essentially in the database I store a record with a min_age and max_age range (this is a fictitious example for the sake of brevity - i am not agist!). My fields look something like the following:

id, cost, savings, min_age, max_age

I essentially have an F# class that acts as a one-to-one mapping with this table - i.e. all properties are mapped exactly to the database fields.

What I would like to do is flatten this range. So, instead of a list containing items like this:

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

I would like a list containing items like this:

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.

Is there any in-built mechanism to flatten a list in this manner and/or does anyone know how to achieve this? Thanks in advance,

JP

4

2 に答える 2

8

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 }  
于 2010-10-25T06:37:24.380 に答える
1

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
于 2010-10-25T11:08:23.853 に答える