2009-08-08 26 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() với hiệu số khác nhau cuối cùng mang lại cho tôi một 'hoạt động không hợp lệ' ngoại lệ với thông tin bổ sung mà 'chuỗi đầu vào có đủ yếu tố'Calling Seq.skip và Seq.take trong F #

tôi cố gắng để hiểu tại sao, như cả Seq.Skip và Seq.take không tạo ra một ngoại lệ theo tài liệu trực tuyến FSharp Collections

Version: (Visual Studio 2010) Beta 1

+2

Tài liệu không nói gì về ngoại lệ; tài liệu chưa hoàn chỉnh. Tôi sẽ gửi một lỗi tài liệu. – Brian

Trả lời

6

cả Seq.skip và Seq.take sẽ ném ngoại lệ này nếu gọi ed với giá trị lớn hơn chuỗi. Bạn có thể kiểm tra mã nguồn trong Seq.fs để xem lý do tại sao:

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

Tôi biết đây là một câu hỏi cũ, nhưng trong trường hợp một người nào đó đi ngang qua đây trong một tìm kiếm cách tôi đã làm:

Bạn có thể sử dụng Seq.truncate nếu bạn muốn tối đa n mục. Nó sẽ không ném một ngoại lệ nếu ít hơn n mục có sẵn.

1

Đối với một exceptionless skip bạn có thể thêm phiên bản của riêng bạn để module Seq như thế này:

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 
     } 

Kết hợp với Seq.truncate (mà là một exceptionless Seq.take tương đương - nó sẽ mất càng nhiều mặt hàng có sẵn mà không cần ném một ngoại lệ).

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

(* returns empty seq *) 
1

Dưới đây là một hơi ngắn "skipSafe" thực hiện bằng cách sử dụng được xây dựng trong các chức năng:

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

Hoặc nếu bạn muốn chỉ inline nó thành đường ống dẫn hiện tại của bạn trực tiếp, thay thế

|> Seq.skip num 

với

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