TL;DR

Когда у вас есть список элементов, например: [a, b, c], и вы хотите получить, например, их линейное распределение с помощью обычной функции .random(), просто создайте ряд элементов в этом списке. в линейном распределении: [a, b, b, c, c, c], а затем получить .random() из этого нового списка — и вы получите результат в линейном распределении:

Вы можете сделать более жесткий или более мягкий угол, добавляя больше или меньше элементов для каждого следующего шага, например:

  • Мягче 45*: [a, b, c, c]
  • Ровно 45*: [а, б, б, в, в, в]
  • Тверже 45*: [a, b, b, b, c, c, c, c, c, c]

И это применимо не только к линейным, но и к любым типам профилей: нормальному распределению, экспоненте, квадрату и т. д. — каждый профиль, каждую кривую можно эмулировать с помощью простой функции .random().

Как я пришел к этому

Я разрабатываю Приложение Product Analytics и оно имеет демо-режим. И у него есть санки (древовидная) диаграмма. Но когда я заполнил диаграмму данными .random(), это выглядело глупо, нереально и неинтересно — высота каждой ветки была примерно одинаковой (что означает: использовали одинаковую по сравнению друг с другом):

Я хотел иметь нормальное распределение для этой диаграммы, чтобы некоторые элементы были узкими, а другие широкими — чтобы было интереснее смотреть и играть с ними. Но в ванильном JavaScript нет встроенной функции для нормального распределения. Вместо этого — длинная дискуссионная ветка на StackOverflow.

Глядя на график нормального распределения, я в конце концов пришел к мысли, что эти вертикальные полосы представляют собой повторение значений X. А это значит, что вместо того, чтобы иметь только одно значение для каждого X в массиве, я могу иметь N значений для каждого X в массиве, а затем передавать функцию .random() среди элементов этого массива — и я получу то, что хочу: случайное, но в той форме, которую я хотел.

Итак, я сделал эту модификацию — увеличил количество элементов:

  • исходный список: [а, б, в, г, д]
  • обычный список распределения: [a, b, b, c, c, c, c, c, d, d, e]

И это сработало:

Видеть? Насколько интересна эта диаграмма по сравнению с оригинальной .random()!

А если мы поместим данные в таблицу, отсортировав значения от максимального к минимальному, то мы увидим, что половинки «колоколообразной кривой» нормального распределения:

Половина кривой из-за сортировки: она сводит все на одну сторону, делая исходную кривую в два раза шире.

Вот почему, когда я хотел смоделировать пользователей и сделать линейную симуляцию, я сделал симуляцию таким же образом и получил это:

А все вместе, вся картина теперь выглядит так:

  • нормальное распределение для диаграммы Санки (дерево) и таблицы ниже с левой стороны,
  • линейное распределение для UserID в центре,
  • и постоянное простое распределение .random() во времени справа:

И все это делается простой и одинаковой единственной функцией .random().

Исходный код для JavaScript

Бонус

Только для тех, кто дочитал до конца!

Поскольку массивы могут быть сложными и тяжелыми, умножение их элементов может дорого стоить вам с точки зрения потребления оперативной памяти. Поэтому вместо умножения самих элементов умножайте их идентификаторы:

  • оригинал: [а, б, в]
  • линейная «плохая практика»: [a, b, b, c, c, c]
  • линейная «хорошая практика»: [0, 1, 1, 2, 2, 2] — идентификаторы для a, b и c

и получить .random() из массива идентификаторов, а затем получить исходный элемент из исходного массива по этому идентификатору.

Надеюсь, вам понравилось и вы весело провели время!