TechEarl

Get a Random Item From an Array in JavaScript (and Shuffle One Correctly)

Pull a random element from an array in JavaScript with one line, then shuffle the whole array correctly with Fisher-Yates. Why arr.sort(() => Math.random() - 0.5) is biased, and when to reach for crypto.getRandomValues instead of Math.random.

Ishan Karunaratne⏱️ 7 min readUpdated
Share thisCopied
Get a random item from a JavaScript array with Math.random, shuffle it correctly with Fisher-Yates, and use crypto.getRandomValues when the pick must be unguessable.

To get a random item from an array in JavaScript, index it with a floored random multiple of its length:

javascript
const fruits = ["apple", "banana", "cherry", "date"];
const pick = fruits[Math.floor(Math.random() * fruits.length)];

Math.random() returns a float in the range 0 (inclusive) to 1 (exclusive). Multiply by length, floor it, and you have a valid index from 0 to length - 1. Because Math.random() never returns exactly 1, you can never overshoot the last index, so there is no off-by-one to guard against. That one line is the whole answer for the common case. The rest of this page is the helper worth keeping, the shuffle the search results keep getting wrong, and the one situation where Math.random() is the wrong tool entirely.

Factor it into a helper

You will reach for this often enough that a named helper beats re-typing the expression and miscounting parentheses:

javascript
const teSample = (arr) => arr[Math.floor(Math.random() * arr.length)];

teSample(["heads", "tails"]); // "heads" or "tails"

Call it teSample (Lodash named the same operation _.sample, so the term is familiar). On an empty array it returns undefined, which is the sensible result. If you need n distinct random items rather than one, do not call teSample in a loop: that can return duplicates. Shuffle the array and take a slice, which brings us to the part most code on the web gets wrong.

Shuffle an array correctly: Fisher-Yates

The shuffle you will see pasted into a hundred answers looks clever and is broken:

javascript
// WRONG: biased, do not use
const bad = arr.sort(() => Math.random() - 0.5);

It is biased. The comparator returns a random sign each time it is called, but Array.prototype.sort does not call it a uniform number of times per element, and the result is that some orderings come up far more often than others. Run that sort a million times over a small array and tally which value lands in position 0: with a correct shuffle each value should appear there equally often, but the random-comparator version skews hard toward leaving elements near where they started. It is not "random enough," it is wrong.

The correct shuffle is Fisher-Yates (the modern Durstenfeld form): walk the array from the end, and for each position swap it with a randomly chosen earlier-or-equal position.

javascript
const teShuffle = (arr) => {
  const out = [...arr]; // copy so the original is untouched
  for (let i = out.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [out[i], out[j]] = [out[j], out[i]];
  }
  return out;
};

This runs in O(n), touches each element once, and produces every permutation with equal probability. Note the i + 1: each element must be allowed to swap with itself (stay put), and getting that bound wrong reintroduces bias. Returning a copy rather than mutating in place is a personal preference; mutating arr directly is fine if the caller expects it, but copying avoids the surprise of a sort-style in-place side effect. To draw n distinct items, shuffle then slice: teShuffle(arr).slice(0, n).

When Math.random is the wrong tool

Math.random() is a pseudo-random generator. It is fast and fine for shuffling a UI carousel or picking a random tip, but its output is not cryptographically secure: per MDN, the values must not be used for anything security-related, because a determined observer can predict them. If the pick must be unguessable, a password reset token, a session ID, a raffle where someone has an incentive to game it, a shuffled deck in a real-money game, use the Web Crypto API instead:

javascript
// Cryptographically secure random index
const teSecureSample = (arr) => {
  const buf = new Uint32Array(1);
  crypto.getRandomValues(buf);
  return arr[buf[0] % arr.length];
};

crypto.getRandomValues() fills a typed array with cryptographically strong random values and is available in browsers and in Node.js (as globalThis.crypto). One caveat: the % arr.length above introduces a small modulo bias when arr.length does not evenly divide 2^32. For most array sizes it is negligible, but if you need a provably uniform secure pick, use rejection sampling (discard values in the unusable top slice of the range and draw again) rather than a bare modulo. For shuffling, swap the Math.random() line inside teShuffle for a crypto.getRandomValues-backed index the same way.

The decision is simple: cosmetic randomness, Math.random(); anything an adversary benefits from predicting, crypto.getRandomValues().

Quick reference

TaskCode
Random itemarr[Math.floor(Math.random() * arr.length)]
Helperconst teSample = (a) => a[Math.floor(Math.random() * a.length)]
Shuffle (correct)Fisher-Yates: swap each i with random j in 0..i
Shuffle (wrong)arr.sort(() => Math.random() - 0.5) is biased
n distinct itemsteShuffle(arr).slice(0, n)
Unguessable pickcrypto.getRandomValues(new Uint32Array(1))

If you are still building the array these operate on, fill an array with default or computed values covers the setup side, and the JavaScript array methods reference is the map of map, filter, slice, and the rest you will combine with these.

FAQ

See also

Sources

Authoritative references this article was fact-checked against.

TagsJavaScriptarraysMath.randomFisher-Yatesshufflecrypto.getRandomValues

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts