开发者

Getting every nth Element of a Sequence

I am looking for a way to create a sequence consisting of every nth element of another sequence, but don't seem to find a way to do that in an elegant way. I can of co开发者_开发技巧urse hack something, but I wonder if there is a library function that I'm not seeing.

The sequence functions whose names end in -i seem to be quite good for the purpose of figuring out when an element is the nth one or (multiple of n)th one, but I can only see iteri and mapi, none of which really lends itself to the task.

Example:

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

Then partial should be [3;6]. Is there anything like it out there?

Edit:

If I am not quite as ambitious and allow for the n to be constant/known, then I've just found that the following should work:

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

Would there be a way to write this shorter?


Seq.choose works nicely in these situations because it allows you do the filter work within the mapi lambda.

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

Similar to here.


You can get the behavior by composing mapi with other functions:

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

The solution using options and choose as suggested by Annon would use only two functions, but the body of the first one would be slightly more complicated (but the principle is essentially the same).

A more efficient version using the IEnumerator object directly isn't too difficult to write:

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 }

EDIT: The snippet is also available here: http://fssnip.net/1R

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜