11
votes

Appeler seq.skip et seq.take en f #

let aBunch = 1000
let offset = 0

let getIt offset =
  MyIEnumerable
  |> Seq.skip aBunch * offset
  |> Seq.take aBunch
  |> Seq.iter ( .. some processing ...)
Calling getIt() with different offsets eventually gives me an 'Invalid operation' exception with additional info that 'the input sequence had insufficient elements'  I try to understand why, as both the Seq.Skip and Seq.take do not generate an exception according to the online documentation FSharp CollectionsVersion: (Visual Studio 2010) Beta 1

1 commentaires

La documentation ne dit rien des exceptions; Les documents sont incomplets. Je déposerai un bogue DOC.


5 Réponses :


7
votes

SEQ.SKIP et SEQ.take lancera cette exception si elle s'appelle une valeur supérieure à la séquence. Vous pouvez vérifier le code source dans seq.fs pour voir pourquoi:

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 }


0 commentaires

27
votes

Je sais que c'est une vieille question, mais au cas où quelqu'un vient à travers cela dans une recherche de la façon dont je l'ai fait:

Vous pouvez utiliser Seq.trunate si Vous voulez au plus n articles. Il ne lancera pas une exception si moins que les articles n sont disponibles.


1 commentaires

Ceci s'applique uniquement à la partie seq.take de la question, pas seq.skip , je suppose?



3
votes

pour un EXCEPTER code> Vous pouvez ajouter votre propre version au module SEQ, comme ceci: xxx pré>

combiné avec seq.trunate code> (qui est un équivalent d'équivalent SEQ.take de code> - il prendra autant d'articles disponibles sans lancer une exception). P>

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

(* returns empty seq *)


0 commentaires

3
votes

Voici une implémentation de "Skipsafe" légèrement plus courte à l'aide de fonctions intégrées:

|> Seq.zip (Seq.initInfinite id)
|> Seq.skipWhile (fun (i, _) -> i < num)
|> Seq.map snd


0 commentaires

1
votes
module Seq = 
    let trySkip count source  =
        source |> Seq.indexed |> Seq.filter(fst >> (<=) count) |> Seq.map snd

0 commentaires