One of the commenters suggested a good approach: pick randomly, just don't pick the last one you picked. At the outline level...
function arrayWithNoRepeat(length) {
const result = [];
for (let i=0; i<length; i++) {
let lastValue = i ? result[i-1] : null;
result.push(randomButNot(lastValue));
}
return result;
}
How to build randomButNot()
? Here are a couple alternatives:
For a small range, build the set of pick-able values and pick one...
// the range of this function is ints 0-9 (except anInt)
function randomButNot(anInt) {
const inBoundsValues = [0,1,2,4,5,6,7,8,9].filter(n => n!==anInt);
const randomIndex = Math.floor(Math.random()*inBoundsValues.length);
return inBoundsValues[randomIndex];
}
For a large range, one idea is to choose in a loop that guards against the duplicate...
// the range is 0-Number.MAX_SAFE_INTEGER (except anInt)
function randomButNot(anInt) {
const choose = () => Math.floor(Math.random()*Number.MAX_SAFE_INTEGER)
let choice = choose();
// we'd have to be very unlucky for this loop to run even once
while (choice === anInt) choice = choose();
return choice;
}
There's a longer discussion about other alternatives relating range size, speed, determinism and uniformity of distribution, but I'll leave it to others smarter than me.