Sized Array Of Random Unique Numbers
Solution 1:
I know this isn't "the lodash way", but it guarantees uniqueness, and allows you to use the same arguments as you were using before. It also scales better than methods that require a binary or linear search through an array, as set.has()
is O(1) on average, rather than O(log(n)) or O(n).
functionuniqRandom (times, ...args) {
const set = newSet()
while (times > 0) {
const rand = _.random(...args)
if (!set.has(rand)) {
set.add(rand)
times--
}
}
returnArray.from(set)
}
console.log(uniqRandom(4, 30, 33));
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
Solution 2:
Much easiear would be...
const uniqRandomNumbers = _.sampleSize(_.range(30, 95), 4);
console.log(uniqRandomNumbers);
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
Solution 3:
I solved it using from a functional programming perspective. refillRandom
is a recursive function that checks the number of items left to generate and calls itself again until the are the required number of items.
It also throws an Error
when is imposible to generate the sequence, if the distance between min
and max
random number is greater than the required unique items. It's better to throw an Error than waiting forever.
constgenerator = (min, offset) => () =>Math.floor(Math.random() * offset + min);
constrefillRandom = (list, min, max, times) => {
const offset = max - min,
num = times - list.length;
if (times > offset) {
thrownewError("Imposible to generate it");
}
const result = _.uniq(_.times(num, generator(min,offset)));
if (result.length < num) {
return result.concat(
refillRandom(list, min, max, num - result.length)
);
}
return result;
}
const r = refillRandom([], 30, 95, 4);
console.log(r);
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
EDIT: I found another solution, I mantain an ordered array of generated numbers and increment the generated number so it get mapped to a number that has not been generated yet. This way I only call random the times
specified.
constrandomGenerator = (min, offset, generated, times) => {
if (!times || !offset) return generated;
var number = Math.floor(Math.random() * offset + min);
const len = generated.length;
for (var i = 0; i < len; i++) {
if (generated[i] <= number) {
number++;
} else {
generated.splice(i, 0, number);
returnrandomGenerator(min, offset - 1, generated, times - 1);
}
}
generated[i] = number;
returnrandomGenerator(min, offset - 1, generated, times - 1);
};
const r = randomGenerator(30, 95 - 30, [], 12);
console.log(r);
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
Post a Comment for "Sized Array Of Random Unique Numbers"