Страницы

Поиск по вопросам

среда, 1 января 2020 г.

JavaScript рандомно заполнить массив элементами из другого массива, чтобы элементы последнего повторялись не более двух раз

#javascript #массивы #алгоритм #случайные_числа


prisvoitcvet();
function prisvoitcvet() {
    let allblock = document.getElementsByClassName('block');
    let arr = cvet();
    let k;
    console.log(allblock);
        for(k = 0; k < allblock.length; k++) {
        let rand = Math.floor(Math.random() * arr.length);
        allblock[k].style.background = arr[rand];
    }
} 


В массив allblock я передал 16 квадратов, изображённых на картинке, а в массиве arr
содержатся 8 рандомных цветов, которые вызывает функция cvet(). Подскажите, пожалуйста,
каким образом можно каждому квадрату присваивать рандомный цвет из массива arr так,
чтобы каждый его элемент повторялся не более 2 раз. Пока что додумался сделать только
то, что у меня в коде, дальше никак...


    


Ответы

Ответ 1



Могу предложить такое решение. Используем массив индексов, с длиной, равной количеству блоков. Из этого массива отбрасываем использованные индексы. // Генерируем массив цветов function cvet() { let result=[ "#5f9ea0", "#ff8c00", "#cd5c5c", "#32cd32", "#4169e1", "#663399", "#808000", "#fff0f5" ]; /* for (const x of Array(8).keys()) { result.push('#' + (0x1000000 + Math.floor(Math.random() * 0x1000000)).toString(16).substr(1)); } */ return result; } function prisvoitcvet() { let allblock = document.getElementsByClassName('block'); let arr = cvet(); //Каждый цвет встречается не более 2 раз let indexes = [...Array(8).keys(),...Array(8).keys()] for (let k = 0; k < allblock.length; k++) { //Случайно выбираем индекс из оставшихся в массиве индексов let index = Math.floor(Math.random() * indexes.length); //Определяем цвет allblock[k].style.background = arr[indexes[index]]; //Отбрасываем использованный индекс indexes.splice(index,1); } } prisvoitcvet(); td { height: 30px; width: 30px; }


Ответ 2



Звучит так, что можно продублировать исходный массив, элементы перемешать и из получившегося массива брать последовательно элементы. let c = Array(8).fill(0).map((z, i) => `hsl(${i*33},55%,55%)`); c = c.concat(c).sort(a => Math.random() - 0.5); [...document.querySelectorAll('.w a')].forEach(b => b.style.backgroundColor = c.pop()) .w { display: grid; grid-template-columns: 44px 44px 44px 44px; grid-template-rows: 44px 44px 44px 44px; } a { margin: 1px; } В общем случае такой подход может быть опасен тем, что сортировка никогда не закончится, однако насколько мне известно в js у Array метод в методе sort реализована сортировка слиянием(merge sort) и проблем с зацикливанием быть не должно. Еще Визуализация let c = Array(88).fill(0).map((z, i) => i - 44); с = c.sort(a=>Math.random()-0.5) update(c) console.log(c.join(',')) function update(data) { d3.select('svg') .selectAll("path") .data(data) .enter() .append("path") .attr("transition", "100ms") .attr('d', 'M0,-22v22') .attr('stroke', 'black') .attr('transform', (d, i) => `translate(${i*3},0) rotate(${d})`); } PS: перемешивать в массивы лучше при помощи алгоритма Кнута - Фишера - Йетса современная версия которого реализована, например в D3.JS в модуле d3.array и представлен методом d3.shuffle Вот вариант похожего алгоритма, не оптимальный по времени из-за используемых методов, зато лаконичный let shuffle = c => { for (var i = c.length; i > -1; i--) c.push(c.splice(Math.floor(Math.random()*i), 1)); } let c0 = Array(88).fill(0).map((z, i) => i - 44); let c1 = [...c0]; d3.select('svg') .selectAll("path") .data(c0) .enter() .append("path") .attr('d', 'M0,-22v22') .attr('stroke', 'black') .attr('transform', d => `translate(${c0.indexOf(d)*3},0) rotate(${d})`); let i = c1.length; shuffle() function shuffle(){ if (i === -1) return c0=[...c1] let n = Math.floor(Math.random()*i); c1.push(c1.splice(n, 1).pop()); i--; d3.select('svg') .selectAll("path") .each(function(d){ if(Math.abs(c0.indexOf(d)-c1.indexOf(d))>2){ let line = d3.select(this); line.attr('stroke', 'red') setTimeout(()=>{ line.attr('stroke', 'black') }, 500) } }) .transition() .duration(200) .attrTween('transform', d => { let x0 = c0.indexOf(d)*3; let x1 = c1.indexOf(d)*3; return t => `translate(${x0+t*(x1-x0)},0) rotate(${d})`; }) setTimeout(shuffle, 210) }

Комментариев нет:

Отправить комментарий