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

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

Wywołanie getIt() z różnych przesunięć w końcu daje mi wyjątek „Nieprawidłowe działanie” z dodatkową informacją, że „sekwencja wejściowa miał wystarczających elementy”Wywołanie Seq.skip i Seq.take w F #

staram zrozumieć, dlaczego, jak i zarówno Seq.Skip Seq.take nie generuje wyjątek według dokumentacji online FSharp Collections

Wersja: (Visual Studio 2010) Beta 1

+2

Dokumentacja nie mówi nic na temat wyjątków; dokumenty są niekompletne. Złożę błąd do dokumentu. – Brian

Odpowiedz

6

zarówno Seq.skip i Seq.take wyrzuci ten wyjątek, jeśli zadzwonisz ed o wartości większej niż sekwencja. Można sprawdzić kod źródłowy w Seq.fs zrozumieć, dlaczego:

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

wiem, jest to stara sprawa, ale w przypadku, gdy ktoś spotyka to w poszukiwanie sposobu robiłam:

ty mogą, użyj Seq.truncate, jeśli chcesz maksymalnien elementów. Nie spowoduje wyjątku, jeśli dostępnych jest mniej elementów niż n.

1

Dla bezwyjątkowy skip można dodać własną wersję z modułem Sekw tak:

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 
     } 

połączonego z Seq.truncate (który jest bezwyjątkowy Seq.take odpowiednik - zajmie tyle przedmiotów są dostępne bez rzucania wyjątek).

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

(* returns empty seq *) 
1

Oto nieco krótsza „skipSafe” realizacja za pomocą wbudowanego w funkcji:

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

lub jeśli chcesz po prostu wbudować go do aktualnej rurociągu bezpośrednio zastąpić

|> Seq.skip num 

z

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