Reputation: 83
The question is: Define a function shuffle :: Int -> [a] -> [a]
that takes a
natural number n and an even-lengthed list, and splits and then riffles the list n times. For example, shuffle 2 [1,2,3,4,5,6] = [1,5,4,3,2,6]
. I have a function riffle that works accordingly, but I don't know how to split a list.
My riffle function is:
riffle :: [a] -> [a] -> [a]
riffle [] ys = ys
riffle xs [] = xs
riffle (x:xs)(y:ys) = x : y : riffle xs ys
I started shuffle, I think, here is what I have:
shuffle :: Int -> [a] -> [a]
shuffle [] = []
shuffle a xs = (length xs) 'div' a
I was attempting to take a list and divide into parts specified "a". I'm new to Haskell and am still not certain how it all works: All help is appreciated.
Upvotes: 0
Views: 703
Reputation: 48611
To split a list in half, with both halves in order, you should generally use a tortoise and hare algorithm.
-- split2 xs = splitAt (length xs `quot` 2) xs
split2 :: [a] -> ([a], [a])
split2 xs0 = go xs0 xs0
where
go (_:_:hs) (t:ts) =
let (front, rear) = go hs ts
in (t:front, rear)
go _ ts = ([], ts)
This should generally be more efficient than calculating the length of the list and dividing by two. It will also work even if the list is infinite.
In this case, however, you don't need a lazy version; you're going to use the second half pretty much immediately. So you can use this more Lisp/Scheme/ML-style version if you prefer:
split2' :: [a] -> ([a], [a])
split2' xs0 = go [] xs0 xs0
where
go front (_:_:hs) (t:ts) = go (t:front) hs ts
go front _ ts = (reverse front, ts)
I'm not sure which will be faster, but split2'
is less susceptible to space leaks introduced by compiler transformations.
Upvotes: 5
Reputation: 67527
not a good shuffle, your first and last elements never move.
something like this?
> let shuffle 0 x = x
shuffle n x = shuffle (n-1) $ uncurry riffle $ splitAt (length x `div` 2) x
or with iterate
Upvotes: 1