我正在寻找一种方法来创建一个由另一个序列的每个第n个元素组成的序列,但似乎找不到以优雅的方式做到这一点的方法。我当然可以破解某些东西,但我想知道是否有一个我没有看到的库函数。
名称以-i结尾的序列函数似乎非常适合于确定元素何时是第n个或(n的多个),但我只能看到iteri
和mapi
,其中没有一个真正适合这项任务。
示例:
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
| _ -> []
有没有办法把它写得更短?
答案 0 :(得分:9)
Seq.choose
在这些情况下效果很好,因为它允许您在filter
lambda中执行mapi
工作。
let everyNth n elements =
elements
|> Seq.mapi (fun i e -> if i % n = n - 1 then Some(e) else None)
|> Seq.choose id
与here类似。
答案 1 :(得分:8)
您可以通过将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建议的选项和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 }
编辑:该片段也可在此处找到:http://fssnip.net/1R