我是 F# 新手,正在寻找一个采用 N* 索引和序列并给我 N 个元素的函数。如果我有 N 个索引,它应该等于 concat Seq.nth index0, Seq.nth index1 .. Seq.nth indexN 但它应该只扫描序列中的 indexN 元素(O(N)),而不是 index0+index1+.. .+索引N (O(N^2))。
总而言之,我正在寻找类似的东西:
//For performance, the index-list should be ordered on input, be padding between elements instead of indexes or be ordered when entering the function
seq {10 .. 20} |> Seq.takeIndexes [0;5;10]
Result: 10,15,20
我可以通过使用 seq { Yield... } 来实现这一点,并在应该传递某些元素时使用索引计数器来标记,但如果 F# 提供了一个很好的标准方法,我宁愿使用它。
谢谢 :)...
添加:我做了以下几点。它有效,但不漂亮。欢迎提出建议
let seqTakeIndexes (indexes : int list) (xs : seq<int>) =
seq {
//Assume indexes is sorted
let e = xs.GetEnumerator()
let i = ref indexes
let curr = ref 0
while e.MoveNext() && not (!i).IsEmpty do
if !curr = List.head !i then
i := (!i).Tail
yield e.Current
curr := !curr + 1
}
当您想通过索引访问元素时,使用序列并不是一个好主意。序列被设计为允许顺序迭代。我会将序列的必要部分转换为数组,然后按索引选择元素:
let takeIndexes ns input =
// Take only elements that we need to access (sequence could be infinite)
let arr = input |> Seq.take (1 + Seq.max ns) |> Array.ofSeq
// Simply pick elements at the specified indices from the array
seq { for index in ns -> arr.[index] }
seq [10 .. 20] |> takeIndexes [0;5;10]
关于你的实现 - 我认为它不能变得更加优雅。在实现需要以交错方式从多个源获取值的函数时,这是一个普遍问题 - 只是没有优雅的方式来编写这些!
但是,您可以使用递归以函数式方式编写此代码,如下所示:
let takeIndexes indices (xs:seq<int>) =
// Iterates over the list of indices recursively
let rec loop (xe:IEnumerator<_>) idx indices = seq {
let next = loop xe (idx + 1)
// If the sequence ends, then end as well
if xe.MoveNext() then
match indices with
| i::indices when idx = i ->
// We're passing the specified index
yield xe.Current
yield! next indices
| _ ->
// Keep waiting for the first index from the list
yield! next indices }
seq {
// Note: 'use' guarantees proper disposal of the source sequence
use xe = xs.GetEnumerator()
yield! loop xe 0 indices }
seq [10 .. 20] |> takeIndexes [0;5;10]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)