Skip to content

Commit

Permalink
feat(weighted): initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
richrdkng committed Aug 23, 2023
1 parent cd7cc48 commit dd243a4
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 0 deletions.
69 changes: 69 additions & 0 deletions packages/weighted/src/RandomWeighted/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { RandomGenerator } from '@grandom/core'

export default class RandomWeighted extends RandomGenerator {
/**
* Returns a value according the weights.
*
* @param weightsWithValues An array of weight-value pairs.
*/
weighted <T extends Array<[number, any]>> (weightsWithValues: T): T[number][1]

/**
* Returns a value according the weights.
*
* @param values An array of values.
* @param weights An array of weights.
*/
weighted <T> (values: T[], weights: number[]): T

weighted (arg1: any, arg2?: any): any {
if (typeof arg1 !== 'undefined') {
const weights: number[] = []
const elements: any[] = []

// process weightsWithValues -----------------------------------------------------------------
if (typeof arg2 === 'undefined') {
if (!Array.isArray(arg1)) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
throw new Error(`weightsWithValues must be an array, got: ${arg1} (typeof === '${typeof arg1}').`)
}

if (arg1.length < 1) {
return
}

for (const weightWithValue of arg1) {
const weight = weightWithValue[0]

if (!(1 in weightWithValue)) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
throw new Error(`value doesn't exist in ${weightWithValue}`)
}

const value = weightWithValue[1]

weights.push(weight)
elements.push(value)
}

return this._engine.nextWeighted(elements, weights)

// process values, and weights ---------------------------------------------------------------
} else {
if (arg1.length < 1) {
return
}

for (let i = 0; i < arg1.length; i++) {
const value = arg1[i]
const weight = arg2[i]

weights.push(weight)
elements.push(value)
}

return this._engine.nextWeighted(elements, weights)
}
}
}
}
7 changes: 7 additions & 0 deletions packages/weighted/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import BasicEngine from '@grandom/engines/basic'
import RandomWeighted from './RandomWeighted'

const random = new RandomWeighted(new BasicEngine())
const weighted = random.weighted.bind(random)

export default weighted
69 changes: 69 additions & 0 deletions packages/weighted/test/RandomWeighted/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { BasicEngine } from '@grandom/engines'
import RandomWeighted from '../../src/RandomWeighted'

const random = new RandomWeighted(new BasicEngine())

describe('RandomWeighted', () => {
describe('.weighted()', () => {
describe('weight-value pair array', () => {
test('empty weight-value array', () => {
expect(random.weighted([])).toBeUndefined()
})

test('weight-value array of length === 1', () => {
for (let i = 0; i < 10_000; i++) {
expect(random.weighted([[1, 'a']])).toBe('a')
}
})

test('weight-value array of length === 2', () => {
for (let i = 0; i < 10_000; i++) {
expect(random.weighted([
[1, 'a'],
[2, 3]
])).toBeOneOf(['a', 3])
}
})

test('weight-value array of length === 3', () => {
for (let i = 0; i < 10_000; i++) {
expect(random.weighted([
[1, 'a'],
[2, 3],
[3, false]
])).toBeOneOf(['a', 3, false])
}
})
})

describe('values array, weights array', () => {
test('empty values, empty weights', () => {
expect(random.weighted([], [])).toBeUndefined()
})

test('1 pair of value-weight', () => {
for (let i = 0; i < 10_000; i++) {
expect(random.weighted(['a'], [1])).toBe('a')
}
})

test('2 pairs of value-weight', () => {
for (let i = 0; i < 10_000; i++) {
expect(random.weighted(
['a', 3],
[1, 2]
)).toBeOneOf(['a', 3])
}
})

test('3 pairs of value-weight', () => {
for (let i = 0; i < 10_000; i++) {
expect(random.weighted(
['a', 3, false],
[1, 2, 3]
)).toBeOneOf(['a', 3, false])
}
})
})
})
})

0 comments on commit dd243a4

Please sign in to comment.