Array#shuffle
Array#shuffle(random: Random) → Array Array#shuffle
Returns the receiver’s elements in a random order, leaving the original untouched. Use it when you need a random permutation: drawing a hand of cards, randomizing a playlist, picking a fair test ordering, choosing which worker gets the next job. If you want the in-place version, that is shuffle! (see the comparison below).
Signature and return value
Array#shuffle(random: Random) → Array
- Returns: a new
Array. The receiver is never modified. - Argument: optional keyword
random:. Any object that responds torand(integer)works in practice, though the docs only guaranteeRandominstances. - Empty source:
[].shufflereturns[]. - Single element:
[42].shufflereturns[42]. - Available since at least Ruby 1.8.7.
Basic Usage
The non-destructive behavior is the detail readers miss most often. shuffle does not replace elements in place; it hands you a brand new instance.
cards = %w[ace king queen jack ten]
hand = cards.shuffle
# => e.g. ["queen", "ten", "ace", "king", "jack"] # order varies per run
cards
# => ["ace", "king", "queen", "jack", "ten"] # original is intact
If you assign the result back to the same variable, you may have looked at the source one too many times and actually wanted shuffle!.
Reproducible Shuffles with random:
Pass random: Random.new(seed) to make the order deterministic. The same seed produces the same permutation, which is exactly what you want in tests, fuzz fixtures, and reproducible demos.
a = [1, 2, 3, 4, 5]
a.shuffle(random: Random.new(1))
# => [4, 2, 5, 1, 3]
a.shuffle(random: Random.new(1))
# => [4, 2, 5, 1, 3] # repeatable: same seed, same order
The random: argument is keyword-only on Ruby 2.0 and later. Calling arr.shuffle(some_rng) positionally raises ArgumentError on modern Ruby, so prefer the keyword form even when the value is short.
Shuffle vs shuffle!
shuffle! mutates the receiver and returns it. One annoying difference shows up on an empty source: shuffle! returns nil, while shuffle returns []. If you ever chain off the bang version, an empty source will blow up with NoMethodError on nil.
arr = [1, 2, 3]
arr.shuffle!.equal?(arr) # => true (bang returns self)
[].shuffle! # => nil (empty case for the bang)
[].shuffle # => [] # non-bang on empty is always []
A simple guard fixes the chaining hazard: arr.shuffle! || arr keeps the empty case safe.
Common Gotchas
- The default PRNG is shared. Calling
Kernel#srand(n)in one test affects every unshuffledarr.shufflelater in the same process, because both useRandom::DEFAULT. Userandom: Random.new(...)to isolate. - Shuffle is a shallow copy. If your elements are mutable (strings, hashes, structs), editing one in the shuffled result also mutates the element in the original.
shuffleis a permutation, not a sort. It does not respect any comparator and is not stable. For “sort then randomize” or “random within buckets”, you have to compose it yourself.- Frozen sources are fine.
[:a, :b, :c].freeze.shufflereturns a fresh copy and does not raise. This is different fromsort!, which refuses to mutate a frozen receiver. - Duck-typed RNGs work, but pass an actual
Randominstance when you can. Custom objects are a debugging tax if anyone wonders where the order came from.
See Also
- Array#sample — pick one or more random elements without permuting the whole thing.
- Array#sort — deterministic ordering, the non-random counterpart to
shuffle. - Ruby Array Methods Guide — a broader tour of the Array API worth bookmarking.