Вопрос или проблема
Скрипт:
let col1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
let col2 = [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
for(let i = 0; i < 5; i++) {
const random = Math.floor(Math.random() * col1.length + 1)
const index = col1.indexOf(random)
const number = col1.at(index)
col1.splice(index, 1)
console.log(number)
}
for(let i = 0; i < 5; i++) {
const random = Math.floor(Math.random() * col2.length + 1)
const index = col2.indexOf(random)
const number = col2.at(index)
col2.splice(index, 1)
console.log(number)
}
Первый цикл for всегда генерирует 5 случайных чисел из первого массива. Но второй цикл for всегда показывает одни и те же результаты (30, 29, 28, 27, 26). Что вызывает такое поведение?
const random = Math.floor(Math.random() * col2.length + 1);
генерирует случайное целое число от 0 до 15, так как col2.length
равно 15
. Затем,
const index = col2.indexOf(random);
всегда возвращает -1
, так как в col2
нет элемента со значением random
. Поэтому
const number = col2.at(index);
всегда присваивает number
последний элемент col2
, который меняется с каждой итерацией, так как
col2.splice(index, 1);
удаляет последний элемент col2
.
Если вы хотите получить пять различных элементов из каждого массива, вы можете просто сделать:
let col1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
let col2 = [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
for(let i = 0; i < 5; i++) {
const index = Math.floor(Math.random() * col1.length);
const number = col1.at(index);
col1.splice(index, 1);
console.log(number);
}
for(let i = 0; i < 5; i++) {
const index = Math.floor(Math.random() * col2.length);
const number = col2.at(index);
col2.splice(index, 1);
console.log(number);
}
ИЗМЕНИТЬ: убран +1
в Math.floor()
, чтобы оставаться в пределах диапазона.
Вы пытаетесь получить индекс значения в col2. У вас массив из 15 элементов. Ваш индекс всегда будет меньше 16 (самого низкого числа во втором наборе), и, соответственно, col2.indexOf(random)
всегда будет возвращать -1, так как ваше случайное значение меньше 16 не содержится в этом массиве, и indexOf возвращает -1, если он не может найти индекс заданного значения. Удаление с -1 вернет последнее значение в вашем массиве, вот почему вы получаете 30-26. См. документацию MDN для indexOf:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
Ваш второй цикл for фактически вызывает at()
с -1
пять раз:
const number = col2.at(-1)
Когда вы передаете -1
в .at()
, он возвращает последний элемент вашего массива, а так как следующий вызов .splice(-1, 1)
удаляет последний элемент из col2
, следующая итерация даст вам следующий последний элемент и так далее.
Основная проблема вашего кода в том, что вы обращаетесь к random
как к элементу вашего массива, а на самом деле это индекс (если вы уберете +1
). Это приводит к тому, что ваш код .indexOf()
не может найти элемент random
в вашем массиве, и, следовательно, устанавливает index
в -1
. Единственная причина, по которой это работает в вашем первом примере, заключается в том, что ваши элементы последовательны, начиная с 1
, так что в этом случае random
совпадает с элементом вашего массива. Но в более общем случае (как col2
), это не так.
Вместо этого вы можете получить свой случайный индекс, получить элемент по этому индексу, используя квадратные скобки (нет необходимости в .indexOf()
или .at()
), а затем удалить элемент из вашего исходного массива (чтобы избежать повторного использования одного и того же элемента):
let col2 = [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30];
for(let i = 0; i < 5; i++) {
const randomIndex = Math.floor(Math.random() * col2.length);
const number = col2[randomIndex];
col2.splice(randomIndex, 1)
console.log(number);
}
Или альтернативный подход — перемешать ваш массив, а затем использовать .slice()
, чтобы получить первые n
элементов:
let col2 = [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30];
// Источник; https://stackoverflow.com/a/12646864/5648954
function shuffle(array) {
for (var i = array.length - 1; i >= 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
const n = 5;
const res = shuffle(col2).slice(0, n);
console.log(res);
Ответ или решение
При разработке на JavaScript, важно учитывать, как генерируются случайные числа и как они используются для извлечения элементов из массивов. В приведённом вами коде действительно существует проблема, из-за которой второй цикл for
всегда возвращает одни и те же значения (30, 29, 28, 27, 26) в каждый из своих повторений. Давайте разберёмся в этом более подробно.
Проблема с кодом
В вашем втором цикле вы используете следующий код для получения случайного числа из массива col2
:
const random = Math.floor(Math.random() * col2.length + 1);
const index = col2.indexOf(random);
Ошибка в расчете случайного числа
Первое, что стоит отметить, это то, что выражение Math.floor(Math.random() * col2.length + 1)
генерирует случайное число от 1 до 15 (включительно), поскольку col2.length
равно 15. Однако элементы в массиве col2
находятся в диапазоне от 16 до 30. Таким образом, indexOf
никогда не найдет совпадений, так как значения, которые вы генерируете, не соответствуют значениям в массиве col2
. В результате col2.indexOf(random)
всегда возвращает -1
.
Влияние на внедрение индекса в массив
Далее, когда index
равен -1
, строка:
const number = col2.at(index);
возвращает последний элемент массива col2
, так как at(-1)
возвращает последний элемент. После этого col2.splice(index, 1)
удаляет последний элемент массива (или, в данном случае, элемент с индексом -1
), что и объясняет, почему вы получаете 30, 29, 28, 27, 26 в результате выполнения этого цикла.
Решение проблемы
Чтобы исправить это, вам необходимо скорректировать способ генерации случайного числа и получения индекса элемента. Вместо использования indexOf
, получите случайный индекс напрямую из массива. Вот исправленный код:
let col1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let col2 = [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30];
// С первого массива
for(let i = 0; i < 5; i++) {
const index = Math.floor(Math.random() * col1.length);
const number = col1[index];
col1.splice(index, 1);
console.log(number);
}
// Со второго массива
for(let i = 0; i < 5; i++) {
const index = Math.floor(Math.random() * col2.length);
const number = col2[index];
col2.splice(index, 1);
console.log(number);
}
Альтернативный подход
Другой подход для выбора нескольких уникальных элементов из массива — это "перемешивание" массива и затем извлечение первых N элементов. Например:
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]]; // Меняем местами элементы
}
return array;
}
const n = 5;
const sampledNumbers = shuffle(col2).slice(0, n);
console.log(sampledNumbers);
Заключение
Таким образом, ошибка в вашем исходном коде вызвана некорректным путем генерации случайного значения, что приводит к постоянному получению одного и того же набора значений. Следуя описанным рекомендациям, вы сможете решить проблему и корректно генерировать уникальные случайные числа из ваших массивов.