← Download MyJS

MyJS block

sample 1.0.0

Picks some items from an array at random, with no item picked twice. Every item is equally likely to be picked, and the picks come back in a random order.

Download with this
Exports
sample
Works in
Browser and Node.js
Requires
random 1.x
Tags
random
The code of version 1.0.0
/**
 * Picks some items from an array at random, with no item picked twice. Every
 * item is equally likely to be picked, and the picks come back in a random
 * order.
 * @template T
 * @param {ArrayLike.<T>|Iterable.<T>} arr
 *    The array, or array-like or iterable object (such as a string or a Set),
 *    to pick from.
 * @param {number} count
 *    How many items to pick, from 0 up to the number of items in `arr`.
 * @param {boolean} [useCrypto=false]
 *    If `true`, uses `crypto.getRandomValues()` instead of `Math.random()`, so
 *    the picks can't be predicted.
 * @returns {Array.<T>}
 *    A new array of `count` items from `arr`. The original isn't changed.
 * @throws {RangeError}
 *    If `count` isn't a whole number from 0 up to the number of items.
 *
 * @example <caption>Drawing lottery numbers</caption>
 * const balls = Array.from({ length: 49 }, (_, i) => i + 1);
 * sample(balls, 6);
 * // → six different numbers, like [23, 7, 41, 2, 38, 15]
 *
 * @example <caption>Picking winners fairly</caption>
 * sample(['Ana', 'Ben', 'Cy', 'Dee', 'Eve'], 2, true);
 * // → two different names, like ['Dee', 'Ana']
 */
function sample(arr, count, useCrypto) {
  const copy = Array.from(arr);
  if (!Number.isInteger(count) || count < 0 || count > copy.length) {
    throw new RangeError(`count must be a whole number from 0 to ${copy.length}.`);
  }
  // Shuffle only the first count places: each gets a random item from the
  // ones not picked yet
  for (let i = 0; i < count; i++) {
    const j = random(i, copy.length, { useCrypto, returnInt: true });
    [copy[i], copy[j]] = [copy[j], copy[i]];
  }
  copy.length = count;
  return copy;
}

Versions

  1. 1.0.0 Oct 23, 2026

    Initial

JSDoc