Вопрос

A machine is turning on and off. seqStartStop is a seq<DateTime*DateTime> that collects the start and end time of the execution of the machine tasks.

I would like to produce the sequence of periods where the machine is idle. In order to do so, I would like to build a sequence of tuples (beginIdle, endIdle).

  • beginIdle corresponds to the stopping time of the machine during the previous cycle.
  • endIdle corresponds to the start time of the current production cycle.

In practice, I have to build (beginIdle, endIdle) by taking the second element of the tuple for i-1 and the fist element of the following tuple i

I was wondering how I could get this task done without converting seqStartStop to an array and then looping through the array in an imperative fashion.

Another idea creating two copies of seqStartStop: one where the head is tail is removed, one where the head is removed (shifting backwards the elements); and then appying map2. I could use skipand take as described here

All these seem rather cumbersome. Is there something more straightforward In general, I was wondering how to execute calculations on elements with different lags in a sequence.

Это было полезно?

Решение

You can implement this pretty easily with Seq.pairwise and Seq.map:

let idleTimes (startStopTimes : seq<DateTime * DateTime>) =
    startStopTimes
    |> Seq.pairwise
    |> Seq.map (fun (_, stop) (start, _) ->
        stop, start)

As for the more general question of executing on sequences with different lag periods, you could implement that by using Seq.skip and Seq.zip to produce a combined sequence with whatever lag period you require.

Другие советы

The idea of using map2 with two copies of the sequence, one slightly shifted by taking the tail of the original sequence, is quite a standard one in functional programming, so I would recommend that route.

The Seq.map2 function is fine with working with lists with different lengths - it just stops when you reach the end of the shorter list - so you don't need to chop the last element of the original copy.

One thing to be careful of is how your original seq<DateTime*DateTime> is calculated. It will be recalculated each time it is enumerated, so with the map2 idea it will be calculated twice. If it's cheap to calculate and doesn't involve side-effects, this is fine. Otherwise, convert it to a list first with List.ofSeq.

You can still use Seq.map2 on lists as a list is an IEnumerable (i.e. a seq). Don't use List.map2 unless the lists are the same length though as it is more picky than Seq.map2.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top