Как получить 5 элементов из массива без повторения?
Я пытаюсь создать онлайн-версию игры в кости с помощью Tumult Hype. Все, что мне нужно сделать, это выбрать 5 имен изображений из массива без повторения. Но я просто не могу заставить его работать.
Я пытался заимствовать код из других ответов stackoverflow, и я не могу заставить их работать.
Код ниже в настоящее время работает, но дает мне повторения. Как мне с этим поработать, чтобы исключить повторы?
(Вы можете увидеть это в действии здесь: https://davebirss.com/storydice/)
Я знаю, что это, вероятно, многословно и неэлегантно. Боюсь, я говорю только на пиджин-джаваскрипте. И то, что я пытаюсь сделать, в настоящее время выходит за рамки моих возможностей.
Заранее благодарим вас за помощь.
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'>";
Спасибо за вашу помощь. Я уверен, что все ответы были отличными, но фрагмент из U25lYWt5IEJhc3RhcmQg — это код, который мне удалось успешно внедрить. Для протокола, вот как я это сделал:
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));
Я неоднократно перезагружала страницу и пока не видела повторов. Идеально!
Возможный дубликат Генерация неповторяющихся случайных чисел в JS
Вы можете взять массив индексов и проверить, существует ли индекс, а затем получить новый индекс или нажать этот индекс.
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.info(indices);
Если ваш count
достаточно мал по сравнению с length
, существует высокая вероятность повторения Math.random()
результатов и последующего continue
, что является пустой тратой времени.
Скопируйте его, затем перетасуйте копию и каждый раз удаляйте первый элемент из массива:
const copy = [...diceRoll].sort(e => 0.5 - Math.random());
И в вашей функции выбора:
const chosen = copy.shift();
Думаю, самое сложное здесь — не тратить производительность впустую, ограничивая возможные варианты теми, которые ранее не были выбраны:
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.info(rollTheDice(images, 5));
Большое спасибо! Ваш подход сделал это для меня! Я добавляю обновление к своему вопросу, чтобы показать, как я вставил его в свой код.
Вам нужна случайная перестановка, в которой все элементы уникальны и из одного набора данных, вот моя реализация:
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]
1. сделать копию массива diceRoll.