Friday, 12 March 2010

SplitEvery (chunk)



open System
open System.Collections.Generic
open System.Linq

//splitEvery :: Int -> [a] -> [[a]]
let splitAt n (xs:IEnumerable<'a>) = (xs.Take n, xs.Skip n)

let rec splitEvery n xs =
    let (ks, vs) = splitAt n xs in
    seq { yield ks
          yield! splitEvery n vs }

6 comments:

Joe W. said...

This seems rather inefficient, since you are enumerating over the enumerable twice for every split. The further you get into the enumerable the worse things are (imagine a 10000 element enumerable split every 10, on the 1000th split you are skipping 9990 elements to get the last 10).

This is the version I use (which, itself, could probably stand some improvement): http://gist.github.com/330586

holoed said...

I agree with you. I like the simplicity of it thought. I will provide a more efficient SplitAt (as soon as I get the time), one that doesn't enumerate twice. Thank you for your comment.

Stringer said...

I have written almost same code too, see my function cut:
http://stackoverflow.com/questions/2649161/need-help-regarding-async-and-fsi
But your function slipEvery do not terminate, I think you should add a test like:
if (vs.Count() <> 0) then yield! splitEvery n vs

Stringer said...

I have written a more efficient solution, yet still readable:
http://gist.github.com/453478

Anonymous said...

But it's cheating if you use mutable types. :)

Stringer said...

“If you know how to cheat, start now.” ;) (quoting a famous Baltimore's baseball player)