Как я могу перемещать элементы из одного массива в другой псевдослучайно, используя хэш?

#javascript #arrays #loops #random #hash

Вопрос:

Представьте два разных массива:

 let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let newArr = [];

 

То, чего я пытаюсь достичь,-это перемещение элементов из arr в newArr через псевдослучайный цикл , который пытается имитировать функциональность Math.random() , за исключением того, что единственная случайность должна идти против фиксированного хэш-числа.

Я пытался что-то в этом роде, но пока не везло:

 const madeUpHash = "827354819373"
const floatIndex = "0."
const f = parseFloat(floatIndex   madeUpHash);

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let newArr = [];

for (let i = 0; i < arr.length; i  ) {
  let ranNum = (f/i); // this points towards 0, meaning the next Math.Floor will eventually always retrieve index 0
    let rand = Math.floor(ranNum * arr.length);
    newArr.push(...arr.splice(rand, 1))
}
 

Это не только не работает, но и довольно ужасно.
Существует ли какой-либо надежный способ добиться этого?
Другой моей идеей было бы перебрать отдельные цифры хэша (после преобразования их в массив) и создать случайное число, такое как ranNum = i/madeUpHash[i] «но», которое сломается, как только i >= madeUpHash[i] оно вернет положительное целое число больше единицы.

Есть какие-нибудь идеи? Спасибо.

Ответ №1:

Я не уверен в том, как люди реализуют Math.random в javascript, но я знаю это в C.

По сути, идея в том, что у вас есть хэш-функция hash и семя s , вы подаете hash(s) заявку , чтобы получить свое X_0 , и для X_(n 1) этого вы делаете X_(n 1) = hash(X_n) .

До тех пор, пока вы выбираете хорошую хэш-функцию с определенным распределением, которое вы хотите для своей случайности, это очень просто и последовательно, если исходное значение одно и то же.

Для C они делают Linear Congruential Generator

 X_(n 1) = (a * X_n   b) % m
 

Таким образом, вы можете использовать свой хэш-номер в качестве посева и сгенерировать серию псевдослучайных чисел. В принципе, вам нужно место для хранения вашего семени и его замены при вызове генератора случайных чисел (и не забудьте применить хэш-функцию).

Случайность полностью зависит от вашего выбора хэш-функции, и нелегко доказать, что вы получаете хорошую хэш-функцию для генерации случайных чисел (например, в большинстве случаев нам нужна хэш-функция равномерного распределения, и производительность тоже имеет значение). Но я верю, что есть литература, которая сделает эти доказательства для вас.

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

1. Интересно, значит, вы используете результат первого хэширования на первой итерации, передаете его в ту же функцию (повторное хэширование результата первого хэширования) и т. Д. И т. Д., Пока не получите желаемый результат?

2. @Ress Это не до тех пор, пока у вас не будет желаемого результата, это ваш результат каждый раз. Поскольку трудно решить, когда вы получите желаемый результат, поэтому хорошая хэш-функция должна возвращать результаты с достаточной случайностью, это просто процесс выбора лучшей хэш-функции. en.cppreference.com/w/cpp/numeric/random На этой странице в разделе Random number engines вы сможете найти различные алгоритмы , реализованные на C/C . Я помню, что они используют очень большую a и c в реализации C

3.@Ress и нашел это en.wikipedia.org/wiki/Linear_congruential_generator для раздела Parameters in common use он описывает значения a c m , используемые во многих реализациях, надеюсь, это поможет.

4. Сама хэш-функция у меня уже есть, просто я не подумал реализовать ее так, как вы упомянули. Всякий раз, когда я вернусь к этому, я попробую это решение. Спасибо!

5. Эй, Санху, я вернулся к этому, чтобы сказать, что твое решение сработало. Большое вам спасибо! Кроме того, у меня была проблема в исходном коде, когда arr.length он менялся из-за сращивания, что означало, что выполнение остановилось на полпути. Просто нужно было заранее сохранить исходную длину в переменной.

Ответ №2:

Почему вы делите ranNum на «я»?

 let rand = Math.floor(f * arr.length);
 

Должно быть все в порядке, потому что вы уменьшаетесь arr.length с каждой итерацией. Кроме того, я не уверен в увеличении i и удалении элемента из массива, что одновременно влияет на состояние цикла. Может быть, просто используйте while петлю.

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

1. Или установите переменную на исходную длину и используйте ее в условии итерации.

2. Проблема с этим решением заключается в том, что значение f*arr.length не будет сильно меняться при каждом уменьшении arr.length . Это будет точно так же, как и в предыдущей итерации, или на 1 меньше.