f # последовательность промежуточных итогов - PullRequest
6 голосов
/ 30 марта 2011

Хорошо, похоже, это должно быть легко, но я просто не понимаю. Если у меня есть последовательность чисел, как мне сгенерировать новую последовательность, составленную из промежуточных итогов? например, для последовательности [1; 2; 3; 4] я хочу отобразить ее на [1; 3; 6; 10]. Соответствующим образом.

Ответы [ 5 ]

15 голосов
/ 30 марта 2011

Использование List.scan:

let runningTotal = List.scan (+) 0 >> List.tail

[1; 2; 3; 4]
|> runningTotal
|> printfn "%A"

Seq.scan реализация на основе:

let runningTotal seq' = (Seq.head seq', Seq.skip 1 seq') ||> Seq.scan (+)

{ 1..4 }
|> runningTotal
|> printfn "%A"
13 голосов
/ 30 марта 2011

Еще один вариант с использованием Seq.scan (Seq.skip 1 избавляет от ведущего нуля):

> {1..4} |> Seq.scan (+) 0 |> Seq.skip 1;;
val it : seq<int> = seq [1; 3; 6; 10]
5 голосов
/ 30 марта 2011
> Seq.scan (fun acc n -> acc + n) 0 [1;2;3;4];;
val it : seq<int> = seq [0; 1; 3; 6; ...]

Со списками:

> [1;2;3;4] |> List.scan (fun acc n -> acc + n) 0 |> List.tail;;
val it : int list = [1; 3; 6; 10]

Редактировать: Другой способ с последовательностями:

let sum s = seq {
    let x = ref 0
    for i in s do
        x := !x + i
        yield !x
}

Да, есть изменяемая переменная, но я считаю ее более читаемой (если вы хотите избавиться от ведущего 0).

0 голосов
/ 24 января 2019

Я подумал, что стоит поделиться с типами записей , как это сделать, на случай, если вы тоже пришли сюда.

Ниже приведен вымышленный пример, демонстрирующий концепцию использования кругов бегуна по дорожке.

type Split = double
type Lap = { Num : int; Split : Split }
type RunnerLap = { Lap : Lap; TotalTime : double }

let lap1 = { Num = 1; Split = 1.23 } 
let lap2 = { Num = 2; Split = 1.13 } 
let lap3 = { Num = 3; Split = 1.03 } 
let laps = [lap1;lap2;lap3]

let runnerLapsAccumulator =  
  Seq.scan 
    (fun rl l -> { rl with Lap = l; TotalTime = rl.TotalTime + l.Split }) // acumulator
    { Lap = { Num = 0; Split = 0.0 }; TotalTime = 0.0 } // initial state

let runnerLaps = laps |> runnerLapsAccumulator
printfn "%A" runnerLaps
0 голосов
/ 30 марта 2011

Не уверен, что это лучший способ, но он должен сделать свое дело

  let input = [1; 2; 3; 4]
  let runningTotal = 
    (input, 0) 
    |> Seq.unfold (fun (list, total) ->
      match list with
      | [] -> 
        None
      | h::t -> 
        let total = total + h
        total, (t, total) |> Some)
    |> List.ofSeq
...