Skip to content

tabatkins/proposal-random-collection-functions

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 

Repository files navigation

Random Collection Functions

  • 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.

Random.shuffle(arr: Array | ArrayLike): undefined

Shuffles an Array (or Array-like) in-place, using a fair shuffling method.

Random.toShuffled(coll: Iterable): Array

Returns a fresh Array containing the contents of coll, shuffled using a fair shuffling method.

Random.take(coll: Iterable, n: Number, options): Array

Returns an Array containing n randomly-selected entries from coll (which must be an iterable).

options are:

  • replace: Boolean: if false (the default), takes without replacement; every value in the returned Array will be from a unique index in coll. (If n is larger than the length of coll (modified by counts), throw a RangeError.) If true, takes with replacement; values in the returned Array 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 from coll. Random.take(["a", "b"], 2, {counts:[2, 3]}) is identical to Random.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 are 1. If the iterable is too short, missing entries are treated as 0; 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 from coll, 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 as 0; if too long, excess entries are ignored. All numbers provided must be non-negative numbers.
  • counts and weights 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 to Random.take(["a", "a", "b", "b", "b"], 2, {weights: [1, 1, 2, 2, 2]}).

Random.takeFromArray(coll: ArrayLike, n: Number, options): Array

Identical in signature and function to Random.take, except that it requires its coll argument (and its counts and weights options) to be Arrays 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).

Random.sample(coll: Iterable, options): Any

Returns a single randomly-selected entry from coll.

options are:

  • counts: Iterable[Number]: identical to take()'s counts option
  • weights: Iterable[Number]: identical to take()'s weights option

(Random.sample(coll, options) is identical to Random.take(coll, 1, options)[0], just more straightforward and without constructing a throwaway Array.)

Random.sampleFromArray(coll: ArrayLike, options): Any

Identical in signature and function to Random.sample, except that it requires its coll argument (and its counts and weights options) to be Arrays or Array-likes.

Random.pop(coll: ArrayLike | Map | Set): Any

Returns a random entry from coll, and mutates coll to remove that entry.

Note

Issue #12 I should propose .pop() on Map and Set.

Interaction with Random.Seeded

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.

History

  • 2025-06: Split out from Random Functions as part of the condition for that proposal advancing to Stage 1.

About

Proposal for a set of new random functions for interacting with "collections" (Arrays, etc)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published