¿Por qué usar una secuencia es mucho más lento que usar una lista en este ejemplo?

Antecedentes: Tengo una secuencia de datos contiguos, con marca de tiempo. La secuencia de datos tiene agujeros, algunos grandes, otros solo un solo valor faltante.
Cuando el agujero es solo un valor faltante, quiero parchear los agujeros con un valor ficticio (los agujeros más grandes se ignorarán).

Me gustaría usar la generación perezosa de la secuencia parcheada, y así estoy usando Seq.unfold.

He hecho dos versiones del método para parchar los agujeros en los datos.

El primero consume elsecuencia de datos con agujeros en ella y produce el parchesecuencia. Esto es lo que quiero, pero los métodos son terriblemente lentos cuando el número de elementos en la secuencia de entrada supera los 1000 y empeora progresivamente a medida que más elementos contiene la secuencia de entrada.

El segundo método consume unlista De los datos con agujeros y produce el parche.secuencia y corre rapido Sin embargo, esto no es lo que quiero, ya que esto fuerza la creación de instancias de toda la lista de entrada en la memoria.

Me gustaría usar el método (secuencia -> secuencia) en lugar del método (lista -> secuencia), para evitar tener toda la lista de entrada en la memoria al mismo tiempo.

Preguntas:

1) ¿Por qué el primer método es tan lento (empeorando progresivamente con las listas de entrada más grandes) (sospecho que tiene que ver con la creación repetida de nuevas secuencias con Seq.skip 1, pero no estoy seguro)

2) ¿Cómo puedo hacer el parcheo de agujeros en los datos rápidamente, mientras uso una entradasecuencia en lugar de una entradalista?

El código:

open System

// Method 1 (Slow)
let insertDummyValuesWhereASingleValueIsMissing1 (timeBetweenContiguousValues : TimeSpan) (values : seq<(DateTime * float)>) =
    let sizeOfHolesToPatch = timeBetweenContiguousValues.Add timeBetweenContiguousValues // Only insert dummy-values when the gap is twice the normal
    (None, values) |> Seq.unfold (fun (prevValue, restOfValues) ->  
        if restOfValues |> Seq.isEmpty then
            None // Reached the end of the input seq
        else
            let currentValue = Seq.hd restOfValues
            if prevValue.IsNone then
                Some(currentValue, (Some(currentValue), Seq.skip 1 restOfValues  )) // Only happens to the first item in the seq
            else
                let currentTime = fst currentValue
                let prevTime = fst prevValue.Value
                let timeDiffBetweenPrevAndCurrentValue = currentTime.Subtract(prevTime)
                if timeDiffBetweenPrevAndCurrentValue = sizeOfHolesToPatch then
                    let dummyValue = (prevTime.Add timeBetweenContiguousValues, 42.0) // 42 is chosen here for obvious reasons, making this comment superfluous
                    Some(dummyValue, (Some(dummyValue), restOfValues))
                else
                    Some(currentValue, (Some(currentValue), Seq.skip 1 restOfValues))) // Either the two values were contiguous, or the gap between them was too large to patch

// Method 2 (Fast)
let insertDummyValuesWhereASingleValueIsMissing2 (timeBetweenContiguousValues : TimeSpan) (values : (DateTime * float) list) =
    let sizeOfHolesToPatch = timeBetweenContiguousValues.Add timeBetweenContiguousValues // Only insert dummy-values when the gap is twice the normal
    (None, values) |> Seq.unfold (fun (prevValue, restOfValues) ->  
        match restOfValues with
        | [] -> None // Reached the end of the input list
        | currentValue::restOfValues -> 
            if prevValue.IsNone then
                Some(currentValue, (Some(currentValue), restOfValues  )) // Only happens to the first item in the list
            else
                let currentTime = fst currentValue
                let prevTime = fst prevValue.Value
                let timeDiffBetweenPrevAndCurrentValue = currentTime.Subtract(prevTime)
                if timeDiffBetweenPrevAndCurrentValue = sizeOfHolesToPatch then
                    let dummyValue = (prevTime.Add timeBetweenContiguousValues, 42.0) 
                    Some(dummyValue, (Some(dummyValue), currentValue::restOfValues))
                else
                    Some(currentValue, (Some(currentValue), restOfValues))) // Either the two values were contiguous, or the gap between them was too large to patch

// Test data
let numbers = {1.0..10000.0}
let contiguousTimeStamps = seq { for n in numbers -> DateTime.Now.AddMinutes(n)}

let dataWithOccationalHoles = Seq.zip contiguousTimeStamps numbers |> Seq.filter (fun (dateTime, num) -> num % 77.0 <> 0.0) // Has a gap in the data every 77 items

let timeBetweenContiguousValues = (new TimeSpan(0,1,0))

// The fast sequence-patching (method 2)
dataWithOccationalHoles |> List.of_seq |> insertDummyValuesWhereASingleValueIsMissing2 timeBetweenContiguousValues |> Seq.iter (fun pair -> printfn "%f %s" (snd pair) ((fst pair).ToString()))

// The SLOOOOOOW sequence-patching (method 1)
dataWithOccationalHoles |> insertDummyValuesWhereASingleValueIsMissing1 timeBetweenContiguousValues |> Seq.iter (fun pair -> printfn "%f %s" (snd pair) ((fst pair).ToString()))

Respuestas a la pregunta(2)

Su respuesta a la pregunta