【问题标题】:Getting every nth Element of a Sequence获取序列的每 n 个元素
【发布时间】:2011-01-15 22:44:32
【问题描述】:

我正在寻找一种方法来创建一个由另一个序列的每个第 n 个元素组成的序列,但似乎没有找到一种优雅的方法来做到这一点。我当然可以破解一些东西,但我想知道是否有我没有看到的库函数。

名称以 -i 结尾的序列函数似乎非常适合确定元素何时是第 n 个或(n 的倍数)第一个,但我只能看到 iteri 和 @987654322 @,没有一个真正适合这项任务。

例子:

let someseq = [1;2;3;4;5;6]
let partial = Seq.magicfunction 3 someseq

那么partial 应该是[3;6]。那里有类似的东西吗?

编辑:

如果我不那么雄心勃勃并允许n 保持不变/已知,那么我刚刚发现以下应该可行:

let rec thirds lst =
    match lst with
    | _::_::x::t -> x::thirds t // corrected after Tomas' comment
    | _ -> []

有没有办法把这个写得更短?

【问题讨论】:

  • 您可以使用mapi 将列表中的每个元素转换为SomeNonefilterNones,然后将map 它们返回到又是未修饰的类型。
  • 您使用列表的解决方案看起来不错(但您可能想编写_::_::x::t(而不是使用元组列表的(_, _, x)::t)。不同之处在于Seq 将与其他集合一起使用列表,但这对您来说可能不是问题。您的列表版本是一个很好的功能代码。
  • 是的,当然,它必须是_::_::x::t,应该在粘贴之前询问编译器。
  • 仍然想知道对于一般情况最有效的解决方案是什么,但是对于我手头的问题,我现在正在使用模式匹配。感谢您花时间回答这个问题。

标签: f#


【解决方案1】:

Seq.choose 在这些情况下工作得很好,因为它允许您在 mapi lambda 中执行 filter 工作。

let everyNth n elements =
    elements
    |> Seq.mapi (fun i e -> if i % n = n - 1 then Some(e) else None)
    |> Seq.choose id

类似于here

【讨论】:

    【解决方案2】:

    您可以通过将mapi 与其他函数组合来获得该行为:

    let everyNth n seq = 
      seq |> Seq.mapi (fun i el -> el, i)              // Add index to element
          |> Seq.filter (fun (el, i) -> i % n = n - 1) // Take every nth element
          |> Seq.map fst                               // Drop index from the result
    

    Annon 建议的使用 options 和 choose 的解决方案将只使用两个函数,但第一个函数的主体会稍微复杂一些(但原理基本相同)。

    直接使用IEnumerator 对象的更高效的版本并不难写:

    let everyNth n (input:seq<_>) = 
      seq { use en = input.GetEnumerator()
            // Call MoveNext at most 'n' times (or return false earlier)
            let rec nextN n = 
              if n = 0 then true
              else en.MoveNext() && (nextN (n - 1)) 
            // While we can move n elements forward...
            while nextN n do
              // Retrun each nth element
              yield en.Current }
    

    编辑:sn-p 也可在此处获得:http://fssnip.net/1R

    【讨论】:

    • 不知道谁更快,你还是'Anon.',但这是相同的建议,不是吗?不过,它看起来效率并不高,是吗?
    • 效率不高(有一些额外的函数调用和间接调用,因为它在后台使用了 3 个迭代器),但它可能还不错(没有中间列表可以分配)。要获得更高效的版本,您将需要突变(在序列表达式中)或使用底层 IEnumerator
    猜你喜欢
    • 2011-07-08
    • 1970-01-01
    • 2021-10-05
    • 2020-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多