2009-08-08 8 views
8
 
let aBunch = 1000 
let offset = 0 

let getIt offset = 
    MyIEnumerable 
    |> Seq.skip aBunch * offset 
    |> Seq.take aBunch 
    |> Seq.iter (.. some processing ...) 

Calling GetIt() con diferentes compensaciones de tiempo me da una 'operación no válida' excepción con la información adicional que 'la secuencia de entrada tenía elementos suficientes'Seq.skip y Seq.take en Fa #

Trato entender por qué, ya que tanto el Seq.Skip y Seq.take no generan una excepción de acuerdo a la documentación en línea FSharp Collections

Versión: (Visual Studio 2010) Beta 1

+2

La documentación no dice nada sobre excepciones; los documentos están incompletos. Archivaré un error de doc. – Brian

Respuesta

6

tanto Seq.skip y Seq.take arrojará esta excepción si llama ed con un valor mayor que la secuencia. Puede comprobar el código fuente en Seq.fs ver por qué:

let skip count (sequence: seq<_>) = 
    { use e = sequence.GetEnumerator() 
     let latest = ref (Unchecked.defaultof<_>) 
     let ok = ref false 
     for i in 1 .. count do 
      if not (e.MoveNext()) then 
       raise <| System.InvalidOperationException "the input sequence had insufficient elements" 
     while e.MoveNext() do 
      yield e.Current } 

let take count (sequence : seq<'T>) = 
    if count < 0 then invalidArg "count" "the number of elements to take may not be negative" 
    (* Note: don't create or dispose any IEnumerable if n = 0 *) 
    if count = 0 then empty else 
    { use e = sequence.GetEnumerator() 
     for i in 0 .. count - 1 do 
      if not (e.MoveNext()) then 
       raise <| System.InvalidOperationException "the input sequence had insufficient elements" 
      yield e.Current } 
20

Sé que esto es una cuestión de edad, pero en caso de que alguien se encuentra con esto en un buscar la manera que lo hice:

Puede use Seq.truncate si quiere como máximo n elementos. No arrojará una excepción si hay menos de n artículos disponibles.

1

Para un sin excepciones skip puede añadir su propia versión del módulo Sec así:

module Seq = 
    let skipSafe (num: int) (source: seq<'a>) : seq<'a> = 
     seq { 
      use e = source.GetEnumerator() 
      let idx = ref 0 
      let loop = ref true 
      while !idx < num && !loop do 
       if not(e.MoveNext()) then 
        loop := false 
       idx := !idx + 1 

      while e.MoveNext() do 
       yield e.Current 
     } 

Combinado con Seq.truncate (que es un sin excepciones Seq.take equivalente - que tomará tanto artículos están disponibles sin lanzar una excepción).

[1..10] 
|> Seq.skipSafe 20 
|> Seq.truncate 5 

(* returns empty seq *) 
1

Aquí hay una aplicación ligeramente más corto "skipSafe" utilizando una función en funciones:

module Seq = 
    let skipSafe num = 
     Seq.zip (Seq.initInfinite id) 
     >> Seq.skipWhile (fun (i, _) -> i < num) 
     >> Seq.map snd 

O si lo desea simplemente inline en su tubería actual directamente, reemplace

|> Seq.skip num 

con

|> Seq.zip (Seq.initInfinite id) 
|> Seq.skipWhile (fun (i, _) -> i < num) 
|> Seq.map snd 
0
module Seq = 
    let trySkip count source = 
     source |> Seq.indexed |> Seq.filter(fst >> (<=) count) |> Seq.map snd 
Cuestiones relacionadas