【问题标题】:Calling Seq.skip and Seq.take in F#在 F# 中调用 Seq.skip 和 Seq.take
【发布时间】:2010-11-17 21:08:47
【问题描述】:
让 aBunch = 1000 让偏移量 = 0 让 getIt 偏移 = MyIEnumerable |> Seq.skip aBunch * offset |> Seq.take aBunch |> Seq.iter ( .. 一些处理 ...)

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

我试图了解原因,因为根据在线文档FSharp Collections,Seq.Skip 和 Seq.take 都不会生成异常

版本:(Visual Studio 2010) Beta 1

【问题讨论】:

  • 文档没有说明异常;文档不完整。我将提交一个文档错误。

标签: f# sequences


【解决方案1】:

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

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

【讨论】:

  • 这仅适用于问题的Seq.take 部分,我猜不适用于Seq.skip?
【解决方案2】:

如果调用的值大于序列,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 }

【讨论】:

    【解决方案3】:

    对于无异常的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 *)
    

    【讨论】:

      【解决方案4】:

      这是一个使用内置函数的略短的“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
      

      【讨论】:

        【解决方案5】:
        module Seq = 
            let trySkip count source  =
                source |> Seq.indexed |> Seq.filter(fst >> (<=) count) |> Seq.map snd
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-07-29
          • 1970-01-01
          • 1970-01-01
          • 2018-01-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多