> pick | shuffle | pair <
// Вставьте список, выберите победителей, перемешайте порядок или разбейте людей на группы - всё в вашем браузере
Выбрать N случайных элементов
Выберите любое количество победителей из вашего списка. Без возвращения для уникальных победителей или с возвращением для розыгрышей во взвешенном стиле.
Несмещённое перемешивание Фишера-Йейтса
Переупорядочивает весь список с помощью классического перемешивания Кнута. Каждая перестановка равновероятна - никаких наивных трюков с сортировкой.
Разбить на группы
Разделите список на пары, тройки или группы любого размера. Идеально для работы в парах, ротаций ревью кода или жеребьёвок «Тайного Санты».
Воспроизводимость с семенем
Укажите строку семени, чтобы получить детерминированный розыгрыш. Одно и то же семя с одним и тем же списком всегда даёт один и тот же результат - им можно делиться и его можно проверять.
// О ИНСТРУМЕНТЕ СЛУЧАЙНОГО ВЫБОРА
Как это работает:
Этот инструмент использует перемешивание Фишера-Йейтса (также известное как перемешивание Кнута): пройдите по массиву от последнего индекса к первому и на каждом шаге поменяйте текущий элемент с элементом по равномерно случайному более раннему индексу. Это даёт несмещённую равномерную перестановку за время O(n). Наивный трюк array.sort(() => Math.random() - 0.5) смещён, потому что компараторы сортировки в JavaScript должны быть транзитивными - случайные компараторы нарушают это и искажают распределение. Для розыгрышей без семени мы берём энтропию из window.crypto.getRandomValues. Когда вы указываете строку семени, мы хешируем её с помощью cyrb53 в 53-битное целое число, а затем запускаем PRNG mulberry32, чтобы одинаковые семена давали одинаковые, воспроизводимые результаты.
Алгоритм:
for i = n-1 down to 1: j = randInt(0, i); swap(a[i], a[j]) - unbiased Fisher-Yates
Стандарты и ссылки:
- >Web Crypto API (W3C) - crypto.getRandomValues для криптографически стойкой случайности
- >Перемешивание Фишера-Йейтса (1938), популяризированное Дональдом Кнутом в The Art of Computer Programming, том 2
- >mulberry32 - маленький, быстрый, хорошо распределённый PRNG с семенем от Tommy Ettinger
- >cyrb53 - 53-битный хеш строки от bryc, используемый для превращения строки семени в числовое состояние PRNG
Распространённые сценарии использования:
- >Раздачи призов, лотереи и определение случайного победителя среди участников
- >Жеребьёвка имён в классе и выбор учеников для неожиданных вопросов
- >Составление спортивных пар, парные тренировки и турнирные сетки
- >Назначение ревьюеров кода в инженерной команде
- >Выбор выборки для A/B-тестов и рандомизированные опросные когорты
- >Пары «Тайного Санты», обмен подарками и напарники для обеда в команде
- >Случайные тестовые данные и семена фаззинга для QA
- >Групповое принятие решений и разрешение ничьих
- >Подбор имитационного жюри и рандомизированные интервью-панели
- >Лотерейные розыгрыши для общественных мероприятий и призов
Связанные инструменты:
- >Генератор случайных чисел — текстовый аналог: выбирайте числа в диапазоне с теми же примитивами воспроизводимости с семенем
- >Генератор UUID — случайные идентификаторы v4, когда нужен уникальный непрозрачный ID, а не победитель из списка
- >Генератор паролей — криптографически случайные строки с управлением набором символов для токенов и учётных данных
- >randompickerwheel.app — интерфейс колеса фортуны, дополняющий этот текстовый выбор, идеально подходит для розыгрышей перед живой аудиторией, вызовов в классе и показа на экране
// ПРИМЕРЫ ВЫБОРА
Розыгрыш — выбрать 3 победителей из 50 участников
> input:
alice@x.com
bob@x.com
carlos@x.com
…(всего 50 строк)
> config:
Режим=Pick N, Количество=3, Разрешить повторы=off, Семя=(пусто)
> output:
1. carlos@x.com
2. priya@x.com
3. wei@x.com
Перемешать список из 10 имён для порядка выступлений
> input:
Alice
Bob
Charlie
Dana
Evelyn
Farouk
Gabriela
Hiroshi
Isabella
Jamal
> config:
Режим=Shuffle, Семя=(пусто)
> output:
1. Hiroshi
2. Alice
3. Farouk
4. Jamal
5. Dana
6. Evelyn
7. Bob
8. Isabella
9. Gabriela
10. Charlie
Разбить класс из 12 учеников на группы по 2
> input:
S01
S02
S03
S04
S05
S06
S07
S08
S09
S10
S11
S12
> config:
Режим=Pair Up, Размер группы=2, Семя=class-2026-05-02
> output:
Группа 1: S07, S02
Группа 2: S11, S04
Группа 3: S09, S12
Группа 4: S01, S06
Группа 5: S03, S10
Группа 6: S08, S05
Воспроизводимый розыгрыш с семенем — запустите дважды с одним и тем же семенем, получите тех же победителей
> input:
alpha
bravo
charlie
delta
echo
foxtrot
golf
hotel
> config:
Режим=Pick N, Количество=2, Семя=launch-day, Разрешить повторы=off
> output:
Запуск 1: 1. echo
2. bravo
Запуск 2: 1. echo
2. bravo (идентично — с семенем)
// ПОЧЕМУ НАИВНЫЙ .SORT() СМЕЩЁН
Распространённое перемешивание в одну строку — arr.sort(() => Math.random() - 0.5). Выглядит элегантно, помещается в одну строку и кажется случайным — но получаемое распределение перестановок далеко от равномерного. Спецификация ECMAScript требует, чтобы функции-компараторы были детерминированными и транзитивными: если a < b и b < c, то a < c. Компаратор «орёл или решка» нарушает этот контракт, и реализация сортировки движка посещает пары сравнения по неравномерному шаблону.
V8 (Chrome, Node) использует Timsort; более старые движки использовали quicksort или mergesort. Каждая реализация посещает разное подмножество пар сравнения и по-разному переиспользует кешированные сравнения. Как эмпирически показал Майк Босток (bost.ocks.org/mike/shuffle/compare.html), наивная сортировка даёт сильно смещённые результаты, при которых некоторые перестановки встречаются в несколько раз чаще других — что недопустимо для розыгрыша, A/B-корзины или любого жребия, который должен быть честным.
Правильный алгоритм — Фишер-Йейтс (перемешивание Кнута): пройдите по массиву от последнего индекса к первому и на каждом шаге поменяйте текущий элемент с элементом, выбранным равномерно случайно среди индексов 0..i. Он работает за O(n), использует O(1) дополнительной памяти и доказуемо даёт каждую перестановку с равной вероятностью.
// BAD: NOT uniformly random
const shuffled = arr.sort(() => Math.random() - 0.5);
// GOOD: Fisher-Yates (Knuth) shuffle
function shuffle(arr) {
const a = arr.slice();
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
// РЕАЛИЗУЙТЕ САМИ
Хотите создать собственный инструмент выбора или проверить наш? Это в точности те примитивы, которые использует эта страница — маленькие, без зависимостей и идентичные тому, что выполняется в вашем браузере при нажатии PICK. Скопируйте их прямо в скрипт Node или другое веб-приложение.
// Fisher-Yates shuffle (uniform, O(n))
function shuffle(arr, rng = Math.random) {
const a = arr.slice();
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(rng() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
// Pick N without replacement (shuffle then slice)
function pickN(arr, n, rng = Math.random) {
if (n > arr.length) {
throw new Error('n exceeds list size');
}
return shuffle(arr, rng).slice(0, n);
}
// mulberry32 seeded PRNG + cyrb53 string hash
// cyrb53: turn a seed string into a 53-bit integer
function cyrb53(str, seed = 0) {
let h1 = 0xdeadbeef ^ seed;
let h2 = 0x41c6ce57 ^ seed;
for (let i = 0, ch; i < str.length; i++) {
ch = str.charCodeAt(i);
h1 = Math.imul(h1 ^ ch, 2654435761);
h2 = Math.imul(h2 ^ ch, 1597334677);
}
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^
Math.imul(h2 ^ (h2 >>> 13), 3266489909);
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^
Math.imul(h1 ^ (h1 >>> 13), 3266489909);
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
}
// mulberry32: tiny seeded PRNG -> [0, 1)
function mulberry32(a) {
return function () {
a |= 0; a = (a + 0x6D2B79F5) | 0;
let t = a;
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
// Build a seeded picker:
const h = cyrb53('my-seed', 1);
const state = (h ^ Math.floor(h / 4294967296)) >>> 0;
const rng = mulberry32(state);
const winners = pickN(['alice', 'bob', 'carlos'], 2, rng);
>> часто задаваемые вопросы
В: Как генерируется случайность?
О: Когда семя не указано, мы используем window.crypto.getRandomValues — криптографически безопасный генератор случайных чисел браузера на основе Web Crypto API. Это тот же источник энтропии, что используется для криптографических ключей и токенов, поэтому его более чем достаточно для лотерей и перемешиваний. Когда вы указываете семя, мы детерминированно выводим 53-битное состояние через хеш строки cyrb53 и подаём его в PRNG mulberry32, чтобы розыгрыш был воспроизводимым.
В: Можно ли получить один и тот же результат дважды, используя семя?
О: Да. Введите любую строку в поле СЕМЯ - дату, название конкурса, хеш, что угодно. Одно и то же семя в сочетании с одним и тем же списком ввода и одним и тем же режимом всегда даст в точности один и тот же результат. Это бесценно для прозрачных розыгрышей, где вы хотите опубликовать семя заранее и дать участникам проверить розыгрыш, или для инженерных ротаций, которые должны быть воспроизводимы на разных машинах.
В: В чём разница между Pick N и Shuffle?
О: Pick N выбирает подмножество размера N из вашего списка, при необходимости с возвращением (повторы разрешены). Shuffle возвращает весь список в переупорядоченном виде - ни один элемент не отбрасывается и не повторяется, только переставляется. Используйте Pick N, когда вам нужно лишь несколько победителей из многих участников; используйте Shuffle, когда каждый элемент по-прежнему должен участвовать, но в новом случайном порядке, например очередь выступлений или плейлист.
В: Действительно ли array.sort(() => Math.random() - 0.5) случаен?
О: Нет, он смещён. Спецификация ECMAScript требует, чтобы компараторы сортировки были детерминированными и транзитивными (если a < b и b < c, то a < c). Случайный компаратор нарушает этот контракт, а разные движки JavaScript выполняют разные базовые алгоритмы сортировки (TimSort, mergesort, quicksort), которые по-разному взаимодействуют со случайным компаратором. Результат — неравномерное распределение, при котором некоторые перестановки встречаются гораздо чаще других. Фишер-Йейтс — это правильный алгоритм.
В: Можно ли разбить на пары список с нечётным количеством элементов?
О: Да. Режим Pair Up перемешивает ваш список с помощью Фишера-Йейтса, а затем разбивает его по выбранному размеру группы. Если общее число не делится нацело, последняя группа будет меньше и чётко помечена в выводе как остаточная группа. Для нечётного списка вы можете либо принять одиночную запись, либо увеличить размер группы, либо перед розыгрышем добавить имя-заполнитель, например «bye».
В: Загружается ли мой список куда-либо?
О: Нет. Этот инструмент работает на 100% на стороне клиента - ваш список, ваше семя и вывод никогда не покидают ваш браузер. Нет ни вызовов сервера, ни логирования, ни аналитики по вводу. Вы можете отключиться от интернета после загрузки страницы, и каждая кнопка по-прежнему будет работать. Обновите страницу — и данные исчезнут навсегда.
В: Есть ли визуальная версия этого инструмента в виде колеса фортуны?
О: Для интерактивного колеса имён с анимацией, звуковыми эффектами и эффектным визуальным показом см. randompickerwheel.app. Это дополнительный продукт, ориентированный на розыгрыши перед живой аудиторией и демонстрацию экрана. Эта страница — текстовый инструмент выбора, ориентированный на большие списки, воспроизводимые розыгрыши с семенем, экспорт CSV и разбиение на пары - полезен, когда нужен быстрый детерминированный ответ, а не презентация.