random-weighted-pick
v2.0.1
Published
Easily choose a random item from a weighted list of items.
Readme
random-weighted-pick
Lightweight utility to pick random items from a weighted list, with probability proportional to each item's weight. Zero external deps. MIT licensed.
Installation
npm install random-weighted-pick- Node:
>=16 - Supports ESM and CommonJS.
Import
// ESM
import weightedPick, { pickMany, createWeightedPicker } from 'random-weighted-pick'
// CommonJS
// const { weightedPick, pickMany, createWeightedPicker } = require('random-weighted-pick')
// or: const weightedPick = require('random-weighted-pick')Quick start
const options = [
{ id: 0, weight: 0.2, item: () => 'Lemon' },
{ id: 1, weight: 0.3, item: ['Grape', 'Orange', 'Apple'] },
{ id: 2, weight: 0.4, item: 'Mango' },
{ id: 3, weight: 0.1, item: 3 },
]
// Weights are normalized automatically (sum does not need to be 1)
const one = weightedPick(options)
console.log(one) // { id: 2, item: 'Mango' }
// Pick multiple (with replacement by default)
const many = pickMany(options, 2)
// Pick multiple without replacement
const noReplacement = pickMany(options, 2, { replacement: false })
// Efficient picker for many selections (alias method by default)
const picker = createWeightedPicker(options, { method: 'alias' })
const next = picker.pick() // { id, item }API
weightedPick(options, config?) => { id: number, item: T }
Pick 1 item according to its weight.
pickMany(options, k, config?) => Array<{ id: number, item: T }>
Pick k items. When replacement: false, sampling is without replacement.
createWeightedPicker(options, config?)
Create an optimized picker for multiple selections.
Returns an object with:
pick(): { id: number, item: T }pickMany(k: number): Array<{ id: number, item: T }>updateWeight(id: number, weight: number): void— updates an item's weight and rebuilds internal structures.
Types
export interface WeightedInput<T> {
id?: number
weight: number
item: T
}
export interface WeightedResult<T> {
id: number
item: T
}
export type RNG = () => number
export interface PickConfig {
normalize?: boolean // default: true
epsilon?: number // default: 1e-12
rng?: RNG // default: crypto.getRandomValues (when available) or Math.random
}
export type Method = 'cdf' | 'alias'pickManyalso accepts{ replacement?: boolean }.createWeightedPickeraccepts{ method?: 'cdf' | 'alias' }.
Options and behavior
- Normalization:
normalize: trueby default. Weights are normalized to sum to 1. Ifnormalize: false, the sum of weights must be 1 (±epsilon). - RNG: defaults to
crypto.getRandomValueswhen available; otherwiseMath.random. You can inject a custom RNG. - Method:
aliasis recommended for many fast selections;cdfuses binary search over the CDF.
Advanced examples
Custom RNG (deterministic for tests)
let i = 0
const values = [0.1, 0.8, 0.4]
const rng = () => values[i++ % values.length]
const result = pickMany([
{ id: 0, weight: 1, item: 'A' },
{ id: 1, weight: 1, item: 'B' },
], 2, { rng })Picker with alias method and weight updates
const picker = createWeightedPicker([
{ id: 0, weight: 1, item: 'A' },
{ id: 1, weight: 2, item: 'B' },
])
picker.pick()
picker.updateWeight(1, 5)
const batch = picker.pickMany(3)Sampling without replacement
const res = pickMany([
{ id: 0, weight: 1, item: 'A' },
{ id: 1, weight: 1, item: 'B' },
{ id: 2, weight: 1, item: 'C' },
], 2, { replacement: false })Errors and validations
- List must be an array of objects.
- Each item must have
weight(finite number ≥ 0) anditem. - If
normalize: false, the sum of weights must be 1 (±epsilon). - RNG must return a number
xin the range [0, 1), and for some internal cases (without replacement) it requires 0 < x < 1.
Size, types and compatibility
- TypeScript types included (
typesin the ESM distribution). - ESM and CJS exports configured via
package.json(exports,import/require).
Development
Requirements: Node 16+
# install dependencies
npm install
# tests
npm test
# coverage
npm run coverage
# build (ESM and CJS)
npm run buildContributing
See CONTRIBUTING.md for guidelines. Please ensure tests and build pass before opening a PR.
License
MIT © KossHackaton OneTeam
