shuffling elements of a list

Ben Finney bignose+hates-spam at benfinney.id.au
Wed May 31 00:20:30 EDT 2006


"greenflame" <alikakakhel at yahoo.com> writes:

> I would like to make a function that takes a list, more specificaly a
> list of strings, and shuffles its elements, like a pile of cards.

Sounds like a job for (ta-da-daa) DSU[0].

That said, here are some comments on your implementation.

> ----------
> testdeck = list('qwertyuiop')
> 
> def pileshuffle(DECK, NUMPILES):

Ouch. Why use uppercase for the parameter names? This implies either
shouting, or constants, neither of which is appropriate.

>     """Split the deck given into NUMPILES piles. Then also put the
> piles""" \
>              """ together to make the deck again."""

Remember that triple-quoted strings don't terminate until the next
triple-quote delimiter. This means not having to close and open them
every newline, which is a primary reason to choose them for doc
strings.

    def pileshuffle(deck, numpiles):
        """ Split the deck bla bla bla
            bla bla bla. """

>     # Define a list of lists which is the piles
>     PILES = [[]] * NUMPILES

More shouting :-(

That will create a list with many references to the *same* list;
almost certainly not what you want. This creates the desired number of
new lists::

        piles = []
        for _ in range(numpiles):
            piles.append(list())

The '_' name is convention for "We're not going to use this
value".

For something more Pythonic, try a list comprehension::

        piles = [list() for _ in range(numpiles)]

>     card = 0
>     pilenum = 0
>     while card < len(DECK):
>         PILES[pilenum].append(DECK[card])
>         card += 1
>         if pilenum < NUMPILES:
>             pilenum += 1
>         else:
>             pilenum = 0

Please don't write C in Python. The 'for' statement allows iteration
directly over a sequence, no need to maintain an index. Also, the
modulus operator is called for with your cycling of the pile index.

        pile_index = 0
        for card in deck:
            piles[pile_index].append(card)
            pile_index = (pile_index + 1) % numpiles

Rather than having the function print the result, it should return it;
that way, the caller gets to decide what happens with the result.

        return piles

Here's my result with your test input::

    >>> def pileshuffle(deck, numpiles):
    ...     """ Split the deck into piles """
    ...     piles = [list() for _ in range(numpiles)]
    ...     pile_index = 0
    ...     for card in deck:
    ...         piles[pile_index].append(card)
    ...         pile_index = (pile_index + 1) % numpiles
    ...     return piles
    ...
    >>> deck = list("qwertyuiop")
    >>> print pileshuffle(deck, 5)
    [['q', 'y'], ['w', 'u'], ['e', 'i'], ['r', 'o'], ['t', 'p']]
    >>> print pileshuffle(deck, 3)
    [['q', 'r', 'u', 'p'], ['w', 't', 'i'], ['e', 'y', 'o']]


For actually implementing this, and to allow the flexibility you said
you wanted, using DSU would be most obvious to me.

[0] Decorate-Sort-Undecorate <URL:http://en.wikipedia.org/wiki/Schwartzian_Transform>

-- 
 \       "Pity the meek, for they shall inherit the earth."  -- Donald |
  `\                                              Robert Perry Marquis |
_o__)                                                                  |
Ben Finney




More information about the Python-list mailing list