Why does random.shuffle return None?

103,791

Solution 1

random.shuffle() changes the x list in place.

Python API methods that alter a structure in-place generally return None, not the modified data structure.

>>> x = ['foo', 'bar', 'black', 'sheep']
>>> random.shuffle(x)
>>> x
['black', 'bar', 'sheep', 'foo']

If you wanted to create a new randomly-shuffled list based on an existing one, where the existing list is kept in order, you could use random.sample() with the full length of the input:

random.sample(x, len(x))     

You could also use sorted() with random.random() for a sorting key:

shuffled = sorted(x, key=lambda k: random.random())

but this invokes sorting (an O(N log N) operation), while sampling to the input length only takes O(N) operations (the same process as random.shuffle() is used, swapping out random values from a shrinking pool).

Demo:

>>> import random
>>> x = ['foo', 'bar', 'black', 'sheep']
>>> random.sample(x, len(x))
['bar', 'sheep', 'black', 'foo']
>>> sorted(x, key=lambda k: random.random())
['sheep', 'foo', 'black', 'bar']
>>> x
['foo', 'bar', 'black', 'sheep']

Solution 2

This method works too.

import random
shuffled = random.sample(original, len(original))

Solution 3

Why, really?

1. Efficiency

shuffle modifies the list in place. This is nice, because copying a large list would be pure overhead if you do not need the original list anymore.

2. Pythonic style

According to the "explicit is better than implicit" principle of pythonic style, returning the list would be a bad idea, because then one might think it is a new one although in fact it is not.

But I don't like it like this!

If you do need a fresh list, you will have to write something like

new_x = list(x)  # make a copy
random.shuffle(new_x)

which is nicely explicit. If you need this idiom frequently, wrap it in a function shuffled (see sorted) that returns new_x.

Solution 4

According to docs:

Shuffle the sequence x in place. The optional argument random is a 0-argument function returning a random float in [0.0, 1.0); by default, this is the function random().

>>> x = ['foo','bar','black','sheep']
>>> from random import shuffle
>>> shuffle(x)
>>> x
['bar', 'black', 'sheep', 'foo']

Solution 5

I had my aha moment with this concept like this:

from random import shuffle
x = ['foo','black','sheep'] #original list
y = list(x) # an independent copy of the original
for i in range(5):
    print shuffle(y) # shuffles the original "in place" prints "None" return
    print x,y #prints original, and shuffled independent copy

>>>
None
['foo', 'black', 'sheep'] ['foo', 'black', 'sheep']
None
['foo', 'black', 'sheep'] ['black', 'foo', 'sheep']
None
['foo', 'black', 'sheep'] ['sheep', 'black', 'foo']
None
['foo', 'black', 'sheep'] ['black', 'foo', 'sheep']
None
['foo', 'black', 'sheep'] ['sheep', 'black', 'foo']
Share:
103,791
alvas
Author by

alvas

食飽未?

Updated on March 13, 2021

Comments

  • alvas
    alvas about 3 years

    Why is random.shuffle returning None in Python?

    >>> x = ['foo','bar','black','sheep']
    >>> from random import shuffle
    >>> print shuffle(x)
    None
    

    How do I get the shuffled value instead of None?

  • torek
    torek almost 11 years
    Is using a random-valued key function truly guaranteed? Some fast sorting algorithms fall over if comparisons are not self-consistent. I can see this working either way, depending on implementation (decorate-sort-undecorate will only need to apply key once on each element so will be well-defined).
  • Martijn Pieters
    Martijn Pieters almost 11 years
    @torek: Python uses decorate-sort-undecorate when sorting with a key callable. So yes, it’s guaranteed as each value is given their random key exactly once.
  • alvas
    alvas about 7 years
    Because python does "copy-by-values" by default instead of pass-by-reference =) stackoverflow.com/a/986495/610569
  • wehnsdaefflae
    wehnsdaefflae over 2 years
    this information is misleading. random.sample(elements, len(elements)) is not equivalent to random.shuffle(elements). the former creates a list of the same length but can contain the same element multiple times as well as some elements not at all. this is exactly what shuffle is meant to avoid by simply reordering the list.
  • wehnsdaefflae
    wehnsdaefflae over 2 years
    this should be the accepted answer
  • Acemad
    Acemad over 2 years
    @wehnsdaefflae: That's not true. random.sample(elements, len(elements)) will not sample the same element twice, nor ignore some elements. I suggest you do a small test to see how it works.
  • wehnsdaefflae
    wehnsdaefflae over 2 years
    yes, you're right. anyone else: pls ignore my previous comment.