2010-10-25 2 views
3

Я новичок в F #, и мне интересно, как я собираюсь сгладить список.F # - Сгладить список/диапазон

По существу в базе данных я храню запись с диапазоном min_age и max_age (для краткости это фиктивный пример - я не против!). Мои поля выглядеть следующим образом:

идентификатор, стоимость, сбережения, min_age, max_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. 

Есть ли встроенный механизм для выравнивания списка таким образом, и/или кто-нибудь знает, как достичь этого? Спасибо заранее,

JP

ответ

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 

Edit: Вы можете также использовать генератор последовательности с выходом!

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

Хороший ответ. Я предполагаю, что OP запрашивает «встроенный механизм», который действительно работает только в том случае, если не было каких-либо пользовательских типов записей, но поскольку это решение выглядит так же элегантно, как и получается. –

+0

Выражение последовательности может быть общим элегантным однострочным слоем: 'let flatten seqOfSeq = seq {для seq в seqOfSeq do yield! сл} '. – MasterMastic

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

Интересное решение :) Конечно, я встречаюсь почти во всех случаях, «хотя все, что выдает значение», почти всегда читается, чем Seq.unfold :) – Juliet

+0

@Juliet Я нахожу, что попытка увидеть случай для библиотечных функций повсюду помогает запомнить их если они станут полезными. :) –

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