From 1ef11a92043054b046eb91294f84b79ecd1165aa Mon Sep 17 00:00:00 2001 From: Peter Sanderson Date: Mon, 14 Oct 2024 14:14:24 +0200 Subject: [PATCH] chore: code improvement for arrayShuffle --- packages/utils/src/arrayShuffle.ts | 9 ++++++--- packages/utils/tests/arrayShuffle.test.ts | 11 ++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/utils/src/arrayShuffle.ts b/packages/utils/src/arrayShuffle.ts index 80fed358b75c..00ccb64e34a6 100644 --- a/packages/utils/src/arrayShuffle.ts +++ b/packages/utils/src/arrayShuffle.ts @@ -1,8 +1,11 @@ /** - * Randomly shuffles the elements in an array. This method - * does not mutate the original array. + * Implementation of the Fisher-Yates shuffle algorithm. + * The algorithm produces an unbiased permutation: every permutation is equally likely. + * @link https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle + * + * This method does not mutate the original array. */ -export const arrayShuffle = (array: readonly T[]) => { +export const arrayShuffle = (array: readonly T[]): T[] => { const shuffled = array.slice(); for (let i = shuffled.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); diff --git a/packages/utils/tests/arrayShuffle.test.ts b/packages/utils/tests/arrayShuffle.test.ts index 46db9c18bf06..cf2a94a5d436 100644 --- a/packages/utils/tests/arrayShuffle.test.ts +++ b/packages/utils/tests/arrayShuffle.test.ts @@ -5,19 +5,24 @@ const SAMPLES = 10000; const TOLERANCE = 0.1; const EXPECTED = SAMPLES / KEYS.length; -describe('arrayShuffle', () => { +const LOWER_BOUND = (1 - TOLERANCE) * EXPECTED; +const UPPER_BOUND = (1 + TOLERANCE) * EXPECTED; + +describe(arrayShuffle.name, () => { it('shuffles randomly', () => { const samples = Object.fromEntries(KEYS.map(key => [key, new Array(KEYS.length).fill(0)])); + for (let sample = 0; sample < SAMPLES; ++sample) { const shuffled = arrayShuffle(KEYS); for (let i = 0; i < shuffled.length; ++i) { samples[shuffled[i]][i]++; } } + KEYS.forEach(key => samples[key].forEach(count => { - expect(count).toBeGreaterThanOrEqual((1 - TOLERANCE) * EXPECTED); - expect(count).toBeLessThanOrEqual((1 + TOLERANCE) * EXPECTED); + expect(count).toBeGreaterThanOrEqual(LOWER_BOUND); + expect(count).toBeLessThanOrEqual(UPPER_BOUND); }), ); });