在 F# 中调用 Seq.skip 和 Seq.take

发布于 2024-08-01 21:22:28 字数 512 浏览 15 评论 0原文

let aBunch = 1000
let offset = 0

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

使用不同的偏移量调用 getIt() 最终会给我一个“无效操作”异常,并附有“输入序列元素不足”的附加信息,

我试图理解为什么,因为 Seq.Skip 和 Seq.take 都不会根据情况生成异常到在线文档 FSharp Collections

版本:(Visual Studio 2010) Beta 1

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 Collections

Version: (Visual Studio 2010) Beta 1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

温柔嚣张 2024-08-08 21:22:28

这是使用内置函数的稍短的“skipSafe”实现:

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

或者,如果您希望直接将其内联到当前管道中,请替换

|> Seq.skip num

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

Here's a slightly shorter "skipSafe" implementation using built in functions:

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

Or if you wish to just inline it into your current pipeline directly, replace

|> Seq.skip num

with

|> Seq.zip (Seq.initInfinite id)
|> Seq.skipWhile (fun (i, _) -> i < num)
|> Seq.map snd
染火枫林 2024-08-08 21:22:28
module Seq = 
    let trySkip count source  =
        source |> Seq.indexed |> Seq.filter(fst >> (<=) count) |> Seq.map snd
module Seq = 
    let trySkip count source  =
        source |> Seq.indexed |> Seq.filter(fst >> (<=) count) |> Seq.map snd
初心未许 2024-08-08 21:22:28

对于无异常的 skip,您可以将自己的版本添加到 Seq 模块,如下所示:

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 
        }

Seq.truncate 结合(这是无异常的 Seq.take 等效 - 它将需要尽可能多的可用项目而不引发异常)。

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

(* returns empty seq *)

For an exceptionless skip you can add your own version to the Seq module like this:

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 
        }

Combined with Seq.truncate (which is an exceptionless Seq.take equivalent - it will take as much items are available without throwing an exception).

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

(* returns empty seq *)
蓝眼泪 2024-08-08 21:22:28

我知道这是一个老问题,但如果有人像我一样在搜索中遇到这个问题:

您可以使用 Seq.truncate 如果您最多需要 n 个项目。 如果可用的项目少于 n 个,它不会抛出异常。

I know this is an old question, but in case someone comes across this in a search the way I did:

You can use Seq.truncate if you want at most n items. It won't throw an exception if fewer than n items are available.

南汐寒笙箫 2024-08-08 21:22:28

如果使用大于序列的值调用,Seq.skip 和 Seq.take 都会抛出此异常。 你可以查看Seq.fs中的源代码来了解原因:

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 }

Both Seq.skip and Seq.take will throw this exception if called with a value larger than the sequence. You can check the source code in Seq.fs to see why:

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 }
烟酉 2024-08-08 21:22:28

对于 skip,您可以通过委托给 LINQ 的 Skip 轻松定义一个具有(大概)最佳性能的简单 skipSafe

open System.Linq

let skipSafe count (source: seq<'a>) = source.Skip(count)

对于 take code>,正如其他答案所说,您可以只使用 Seq.truncate,或者可选地为其别名:

let takeSafe count source = Seq.truncate count source

For skip, you can easily define a trivial skipSafe with (presumably) optimal performance by delegating to LINQ's Skip:

open System.Linq

let skipSafe count (source: seq<'a>) = source.Skip(count)

For take, as the other answers say, you can just use Seq.truncate, or optionally alias it:

let takeSafe count source = Seq.truncate count source
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文