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 }


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):

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 Bell said...

I have written almost same code too, see my function cut:
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:

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)