Reputation: 23
How do I get 5 elements from an array without repetition?
I'm trying to create an online version of story dice using Tumult Hype. All that I need to do is choose 5 image names from an array without repetition. But I just can't get it to work.
I've tried borrowing code from other stackoverflow answers and I can't get them working.
The code below is currently working but gives me repeats. How do I tinker with it to eliminate the repeats?
(You can see it in action here: https://davebirss.com/storydice/)
I know that it's probably verbose and inelegant. I only speak pidgin javascript, I'm afraid. And what I'm trying to do is currently beyond my ability.
Thank you so much in advance for your help.
var diceRoll = ['${resourcesFolderName}/story_dice1.png',
'${resourcesFolderName}/story_dice2.png',
'${resourcesFolderName}/story_dice3.png',
...,
'${resourcesFolderName}/story_dice51.png']
function choose(n, arr) {
while (arr.length > n) {
var del = Math.floor(Math.random() * arr.length);
arr = arr.filter(function(item, i) {
return i !== del;
});
}
return arr;}
var result1 = [choose(1, diceRoll)];
var result2 = [choose(1, diceRoll)];
var result3 = [choose(1, diceRoll)];
var result4 = [choose(1, diceRoll)];
var result5 = [choose(1, diceRoll)];
hypeDocument.getElementById("dice1").innerHTML = "<img src='"+result1+" 'height='125' width='125'>";
hypeDocument.getElementById("dice2").innerHTML = "<img src='"+result2+" 'height='125' width='125'>";
hypeDocument.getElementById("dice3").innerHTML = "<img src='"+result3+" 'height='125' width='125'>";
hypeDocument.getElementById("dice4").innerHTML = "<img src='"+result4+" 'height='125' width='125'>";
hypeDocument.getElementById("dice5").innerHTML = "<img src='"+result5+" 'height='125' width='125'>";
Thank you all for your help. I'm sure all the answers were great but the snippet from U25lYWt5IEJhc3RhcmQg is the code that I managed to successfully incorporate. For the record, this is how I did it:
const rollTheDice = (arr, n) => {
const randomN = [];
while(randomN.length < n){
const randomIndex = Math.floor(Math.random()*arr.length);
randomN.push(arr[randomIndex]);
arr.splice(randomIndex, 1);
}
return randomN;}
var result1 = (rollTheDice(images,1));
var result2 = (rollTheDice(images,1));
var result3 = (rollTheDice(images,1));
var result4 = (rollTheDice(images,1));
var result5 = (rollTheDice(images,1));
I've been repeatedly reloading the page and haven't seen any repeats yet. Perfect!
Upvotes: 2
Views: 459
Reputation: 15530
I guess, the trickiest part here is not to waste the performance, limiting possible options to those, not previously chosen:
const images = ['a','b','c','d','e','f'];
const rollTheDice = (arr, n) => {
const randomN = [];
while(randomN.length < n){
const randomIndex = Math.floor(Math.random()*arr.length);
randomN.push(arr[randomIndex]);
arr.splice(randomIndex, 1);
}
return randomN;
}
console.log(rollTheDice(images, 5));
Upvotes: 0
Reputation: 491
You want a random permutation which all elements is uniq and from one dataset, here is my implementation:
var array = [1, 2, 3, 4, 5, 6];
/**
* uniqGet
* @param {*} array source array
* @param {*} num how many elements to get
*/
function uniqGet(array, num) {
if (array.length < num) {
throw new Error("num should less than options");
}
let res = [];
while (num > 0) {
let index = Math.floor(Math.random() * array.length);
res.push(array[index]);
array.splice(index, 1);
num--;
}
return res;
}
let result = uniqGet(array, 3); // [x, y, z]
Upvotes: 0
Reputation: 44105
Copy it, then shuffle the copy, and remove the first element from the array each time:
const copy = [...diceRoll].sort(e => 0.5 - Math.random());
And in your choosing function:
const chosen = copy.shift();
Upvotes: 0
Reputation: 386654
You could take an array of indices and check if the index exist, then get a new index or push this index.
var length = 51, // your count of items
indices = [], // the result set with indices
count = 5, // the amount of wanted indices
random; // guess what?
while (indices.length < count) { // check length
random = Math.floor(Math.random() * length); // get random value
if (indices.includes(random)) continue; // continue if already selected
indices.push(random); // if not take it
}
console.log(indices);
Upvotes: 1
Reputation: 151
Upvotes: 0