# dealing out 5 hands of cards, each containing 5 cards

Submitted by metaperl on Sun, 09/04/2005 - 10:22pm.

I helped someone out in `#haskell` with the problem stated in the subject by writing the code below. I'm a bit rusty (and never was very good) at Haskell, so any pointers on how to improve the code I supplied to him are appreciated.

``` cards = [1..52] dropAmount = [ d*5 | d <- [0 .. 4 ] ] hand cards = map (\d -> (take 5 \$ drop d cards)) dropAmount ```

Choose whatever you can read and understand.

I think I like this one best:
`hand = take 5 . List.unfoldr (\l -> Just (take 5 l, drop 5 l))`

This works too:
`hand cards = take 5 \$ map (take 5 . (`drop` cards)) [0,5..]`

Making dtlin's first solution even more succint (and probably less readable to beginners), use the Prelude function splitAt, which combines take and drop. So:

``` hands = take 5 . List.unfoldr (Just . splitAt 5) ```

I came up with two approaches, although I agree that whatever you (or he) find most readable is best. I generalized the problem slightly to dealing `N` hands of `M` cards out of a deck.

Here was my first solution:
``` dealHands :: Int -> Int -> [a] -> [[a]] dealHands handSize numHands deck = take numHands \$ allHands handSize deck     where allHands handSize deck =               let (hand, deck') = splitAt handSize deck                   fullHand = length hand == handSize                   remaining = allHands handSize deck'               in if fullHand                  then hand:remaining                  else [] ```

And the second (which can be made much more succinct):
``` dealHands :: Int -> Int -> [a] -> [[a]] dealHands handSize numHands deck =     let         -- Decks with the top handSize cards successively removed         decks = iterate (drop handSize) deck           -- The top handSize cards from each of the above decks         potentialHands = map (take handSize) decks           -- All hands of handSize from the deck, down to a hand with not         -- enough cards (the deck is exhausted)         allHands = takeWhile fullHand potentialHands       in -- Get the top numHands hands from all possible hands         take numHands allHands       where         -- Return whether this hand has a sufficient number of cards         fullHand hand = length hand == handSize ```

Hmm, `hand = take 5 . map (take 5) . iterate (drop 5)` (stolen from the above) is possibly more elegant than `hand = take 5 . List.unfoldr (Just . splitAt 5)`.  Very nice.

And I think that the `fullHand` checks are silly... I'd be perfectly happy with `dealHands 2 2 [1] == [[1], []]`.

## Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.