- Stage 0
- Authors: WhosyVox and Tab Atkins-Bittner
- Champions: Tab Atkins-Bittner
- Spec Text: currently this README
This proposal introduces several new functions for interacting with "collections" (iterables, Arrays, Maps, Sets, etc)
in a random manner.
This proposal stands alongside Simple Random Functions and Random Non-Uniform Distributions, and like those, uses the Random
namespace object introduced by Seeded Random.
Shuffles an Array
(or Array
-like) in-place, using a fair shuffling method.
Returns a fresh Array
containing the contents of coll
,
shuffled using a fair shuffling method.
Returns an Array
containing n
randomly-selected entries from coll
(which must be an iterable).
options
are:
replace: Boolean
: iffalse
(the default), takes without replacement; every value in the returnedArray
will be from a unique index incoll
. (Ifn
is larger than the length ofcoll
(modified bycounts
), throw aRangeError
.) Iftrue
, takes with replacement; values in the returnedArray
can be repeats (and you can take any amount of them without error).counts: Iterable[Number]
: provides the "multiplicity" of the entries in the matching index fromcoll
.Random.take(["a", "b"], 2, {counts:[2, 3]})
is identical toRandom.take(["a", "a", "b", "b", "b"], 2)
. (In particular, this example could return "a" or "b" multiple times, even tho it's not using replacement, just like the desugared example can.) If omitted, all counts are1
. If the iterable is too short, missing entries are treated as0
; if too long, excess entries are ignored. All numbers provided must be non-negative integers.weights: Iterable[Number]
: provides the "weight" for the entries in the matching index fromcoll
, allowing some entries to be more likely to be selected than others. If omitted, all entries have equal weight. If the iterable is too short, missing entries are treated as0
; if too long, excess entries are ignored. All numbers provided must be non-negative numbers.counts
andweights
can be used together; the specified weight for an entry is treated as applying to each of the multiple implied entries (not divided between them). That is,Random.take(["a", "b"], 2, {counts: [2, 3], weights:[1, 2]})
is equivalent toRandom.take(["a", "a", "b", "b", "b"], 2, {weights: [1, 1, 2, 2, 2]})
.
Identical in signature and function to Random.take
,
except that it requires its coll
argument (and its counts
and weights
options) to be Array
s or Array
-likes.
Note
Issue #4 discusses the justification for this.
A random-access collection has significantly different optimal take()
performance characteristics (a single random sample, and constant time and memory) than an iterable collection (either a single random sample but O(n) time and memory, or O(log(n)) random samples, O(1) memory, and O(n) time).
Returns a single randomly-selected entry from coll
.
options
are:
counts: Iterable[Number]
: identical totake()
'scounts
optionweights: Iterable[Number]
: identical totake()
'sweights
option
(Random.sample(coll, options)
is identical to Random.take(coll, 1, options)[0]
, just more straightforward and without constructing a throwaway Array
.)
Identical in signature and function to Random.sample
,
except that it requires its coll
argument (and its counts
and weights
options) to be Array
s or Array
-likes.
Returns a random entry from coll
, and mutates coll
to remove that entry.
Note
Issue #12
I should propose .pop()
on Map
and Set
.
All of the above functions will also be defined on the Random.Seeded
class as methods, with identical signatures and behavior. That is, Random.take(...)
and new SeededRandom(...).take(...)
will both work.
Precise generation algorithms will be defined for the Random.Seeded
methods, to ensure reproducibility. It's recommended that the Random
versions use the same algorithm, but not strictly required; doing so just lets you use an internal Random.Seeded
object and avoid implementing the same function twice.
- 2025-06: Split out from Random Functions as part of the condition for that proposal advancing to Stage 1.