# [raleigh.rb] The Ruby shuffle

Wed Dec 17 15:28:57 EST 2008

```A friend of mine mentioned a little algorithm for shuffling a deck of
cards by splitting it in half and interleaving cards from each half. In
Ruby, I came up with the following:

def shuffle xs
n = xs.length / 2
xs[0...n].zip(xs[n..-1]).flatten
end

then shortened a bit to compare with various Haskell versions below:

shuffle = lambda {|xs| n = xs.length / 2; xs[0...n].zip(xs[n..-1]).flatten }

I know this is a Ruby list, but I thought I'd share the Haskell versions
I collected (mostly from others except for the 1st two) while
experimenting.

I think Ruby compares favorably to Haskell (except for speed) on this
exercise even though Haskell shines on this type of problem.

shuffle1 xs = concat [[fst x, snd x] | x <- uncurry zip (splitAt (length
xs `div` 2) xs)]

-- My second attempt. Create a flatten_tup2 function: [(a,b),(c,d)] =>
[a,b,c,d]
shuffle2 xs = flatten_tup2 (uncurry zip (splitAt (length xs `div` 2) xs))
where
flatten_tup2 [] = []
flatten_tup2 ((a,b):xs) = a : b : flatten_tup2 xs

-- Implement flatten_tup2 with foldr
shuffle3 xs = flatten_tup2 (uncurry zip (splitAt (length xs `div` 2) xs))
where
flatten_tup2 = foldr (\(a,b) c -> a:b:c) []

shuffle4 xs = do (x,y) <- uncurry zip (splitAt (length xs `div` 2) xs);
[x,y]

shuffle5 xs = [z | (x,y) <- uncurry zip (splitAt (length xs `div` 2)
xs), z <- [x,y]]

-- discovered parallel comprehensions. requires: ghci -XParallelListComp
-- using | instead of , causes the generators to operate in parallel
shuffle6 xs = concat [[x,y] | x <- left | y <- right]
where
(left, right) = splitAt (length xs `div` 2) xs

-- compare to shuffle1 - remove fst, snd by pattern matching
shuffle7 xs = concat [[x,y] | (x,y) <- uncurry zip (splitAt (length xs
`div` 2) xs)]

-- interleave operator "AFAIK by Mark Jones"
(/\/) :: [a] -> [a] -> [a]
[]     /\/ ys = ys
(x:xs) /\/ ys = x : (ys /\/ xs)
shuffle8 xs = uncurry (/\/) \$ splitAt (length xs `div` 2) \$ xs

-- using parallel list comprehensions (same as mine above)
shuffle9 xs = concat [[a, b] | a <- l1 | b <- l2]
where (l1, l2) = splitAt (length xs `div` 2) xs

-- w/o list comprehensions
shuffle10 xs = concat (zipWith (\a b -> [a, b]) l1 l2)
where (l1, l2) = splitAt (length xs `div` 2) xs

-- different algorithm, but interesting
everySnd []  = []
everySnd [x] = [x]
everySnd (x:_:xs) = x : everySnd xs
shuffle9 xs = everySnd xs ++ everySnd (tail xs)

--