У мене такий масив:
var arr1 = ["a", "b", "c", "d"];
Як я можу його рандомізувати / перетасувати?
У мене такий масив:
var arr1 = ["a", "b", "c", "d"];
Як я можу його рандомізувати / перетасувати?
Відповіді:
Алгоритм фактичного неупередженого переміщення - перемішання Фішера-Йейта (він же Кнут).
Дивіться https://github.com/coolaj86/knuth-shuffle
Ви можете побачити чудову візуалізацію тут (і оригінальну публікацію, пов’язану з цим )
function shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
// Used like so
var arr = [2, 11, 37, 42];
shuffle(arr);
console.log(arr);
Ще трохи інформації про використовуваний алгоритм .
i--
НЕ --i
. Крім того , тест if (i==0)...
є зайвим , тому що якщо в той час як петля ніколи не буде введений. Заклик до можна зробити швидше за допомогою . Або tempi, або tempj можна видалити, а значення безпосередньо призначити myArray [i] або j, якщо це доречно. i == 0
Math.floor
...| 0
0 !== currentIndex
).
Ось реалізація JavaScript перекладу Durstenfeld , оптимізованої версії Fisher-Yates:
/* Randomize array in-place using Durstenfeld shuffle algorithm */
function shuffleArray(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;
}
}
Він підбирає випадковий елемент для кожного оригінального елемента масиву та виключає його з наступного малювання, як вибір випадковим чином з колоди карт.
Це розумне виключення замінює вибраний елемент поточним, потім вибирає наступний випадковий елемент із залишку, циклічно повертаючись назад для досягнення оптимальної ефективності, забезпечуючи спрощення випадкового вибору (він завжди може починатися з 0) і тим самим пропускає кінцевий елемент.
Алгоритм виконання O(n)
. Зауважте, що переміщення виконується на місці, тому якщо ви не хочете змінювати оригінальний масив, спершу зробіть його копію .slice(0)
.
Новий ES6 дозволяє нам призначити дві змінні одночасно. Це особливо зручно, коли ми хочемо поміняти значення двох змінних, оскільки це можна зробити в одному рядку коду. Ось коротша форма тієї самої функції, що використовує цю функцію.
function shuffleArray(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
оскільки JavaScript передає масиви за посиланням при використанні в якості аргументів функції. Я припускаю, що це економить на просторі стека, але це маленька цікава функція. Виконання перетасовки на масиві перемістить початковий масив.
Math.random() should not be multiplied with the loop counter + 1, but with
array.lengt () `. Див. Як генерувати випадкові цілі числа в JavaScript у визначеному діапазоні? для дуже вичерпного пояснення.
Увага!
Використання цього алгоритму не рекомендується , оскільки він неефективний і сильно упереджений ; дивитись коментарі. Тут його залишають для подальшого ознайомлення, оскільки ідея не така вже й рідкісна.
[1,2,3,4,5,6].sort(function() {
return .5 - Math.random();
});
Можна було (або слід) використовувати його як прототип від масиву:
Від ChristopheD:
Array.prototype.shuffle = function() {
var i = this.length, j, temp;
if ( i == 0 ) return this;
while ( --i ) {
j = Math.floor( Math.random() * ( i + 1 ) );
temp = this[i];
this[i] = this[j];
this[j] = temp;
}
return this;
}
for...in
петлі для ітерації над масивами.
Ви можете легко це зробити за допомогою карти та сортування:
let unshuffled = ['hello', 'a', 't', 'q', 1, 2, 3, {cats: true}]
let shuffled = unshuffled
.map((a) => ({sort: Math.random(), value: a}))
.sort((a, b) => a.sort - b.sort)
.map((a) => a.value)
Ви можете перетасувати поліморфні масиви, і сортування таке ж випадкове, як Math.random, що досить добре для більшості цілей.
Оскільки елементи сортуються за послідовними ключами, які не регенеруються під час кожної ітерації, і кожне порівняння виводиться з одного і того ж розподілу, будь-яка невипадковість у розподілі Math.random скасовується.
Швидкість
Часова складність - O (N log N), така ж, як і швидке сортування. Космічна складність становить O (N). Це не так ефективно, як перемикання Фішера Йейтса, але, на мій погляд, код значно коротший і функціональніший. Якщо у вас є великий масив, ви, звичайно, повинні використовувати Fischer Yates. Якщо у вас є невеликий масив з кількома сотнями елементів, ви можете це зробити.
Використовуйте бібліотеку underscore.js. Метод _.shuffle()
приємний для даного випадку. Ось приклад із методом:
var _ = require("underscore");
var arr = [1,2,3,4,5,6];
// Testing _.shuffle
var testShuffle = function () {
var indexOne = 0;
var stObj = {
'0': 0,
'1': 1,
'2': 2,
'3': 3,
'4': 4,
'5': 5
};
for (var i = 0; i < 1000; i++) {
arr = _.shuffle(arr);
indexOne = _.indexOf(arr, 1);
stObj[indexOne] ++;
}
console.log(stObj);
};
testShuffle();
shuffle
функції.
НОВИЙ!
Коротше і, ймовірно, * швидший алгоритм переміщення Fisher-Yates
function fy(a,b,c,d){//array,placeholder,placeholder,placeholder
c=a.length;while(c)b=Math.random()*(--c+1)|0,d=a[c],a[c]=a[b],a[b]=d
}
Розмір сценарію (з fy як ім'я функції): 90 байт
DEMO http://jsfiddle.net/vvpoma8w/
* швидше, ймовірно, у всіх браузерах, крім хромованих.
Якщо у вас є якісь питання, просто запитайте.
EDIT
так, це швидше
ВИКОНАННЯ: http://jsperf.com/fyshuffle
використовуючи головні функції.
EDIT Був підрахунок перевищення (не потрібно --c + 1), і ніхто не помітив
коротше (4 байти) та швидше (протестуйте!).
function fy(a,b,c,d){//array,placeholder,placeholder,placeholder
c=a.length;while(c)b=Math.random()*c--|0,d=a[c],a[c]=a[b],a[b]=d
}
Кешування в іншому місці, var rnd=Math.random
а потім використання rnd()
також трохи збільшить продуктивність на великих масивах.
http://jsfiddle.net/vvpoma8w/2/
Читаема версія (використовуйте оригінальну версію. Це повільніше, пара даремна, як закриття & ";", сам код також коротший ... можливо, прочитайте це Як "мінімізувати" код Javascript , btw ви не можете стиснути наступний код у minifiers javascript, як у вищезгаданому.)
function fisherYates( array ){
var count = array.length,
randomnumber,
temp;
while( count ){
randomnumber = Math.random() * count-- | 0;
temp = array[count];
array[count] = array[randomnumber];
array[randomnumber] = temp
}
}
fy
і shuffle prototype
, я fy
постійно дістаюсь внизу в Chrome 37 на OS X 10.9.5 (81% повільніше ~ 20k ops порівняно з ~ 100k) і Safari 7.1 це на ~ 8% повільніше. YMMV, але це не завжди швидше. jsperf.com/fyshuffle/3
Редагувати: Ця відповідь невірна
Дивіться коментарі та https://stackoverflow.com/a/18650169/28234 . Тут його залишають для довідки, оскільки ідея не рідкість.
Дуже простий спосіб для малих масивів - це просто такий:
const someArray = [1, 2, 3, 4, 5];
someArray.sort(() => Math.random() - 0.5);
Це, мабуть, не дуже ефективно, але для малих масивів це працює чудово. Ось приклад, щоб ви могли бачити, наскільки це випадково (чи ні), і чи відповідає він вашому користувальницькому чи ні.
const resultsEl = document.querySelector('#results');
const buttonEl = document.querySelector('#trigger');
const generateArrayAndRandomize = () => {
const someArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
someArray.sort(() => Math.random() - 0.5);
return someArray;
};
const renderResultsToDom = (results, el) => {
el.innerHTML = results.join(' ');
};
buttonEl.addEventListener('click', () => renderResultsToDom(generateArrayAndRandomize(), resultsEl));
<h1>Randomize!</h1>
<button id="trigger">Generate</button>
<p id="results">0 1 2 3 4 5 6 7 8 9</p>
Деякі рішення на цій сторінці не є надійними (вони лише частково рандомізують масив). Інші рішення значно менш ефективні. За допомогою testShuffleArrayFun
(див. Нижче) ми можемо протестувати функції перетасування масиву для надійності та продуктивності. Наступні рішення: надійні, ефективні та короткі (з використанням синтаксису ES6)
[Порівняльні тести проводилися з використанням testShuffleArrayFun
інших рішень у Google Chrome]
Перемішати масив на місці
function getShuffledArr (array){
for (var i = array.length - 1; i > 0; i--) {
var rand = Math.floor(Math.random() * (i + 1));
[array[i], array[rand]] = [array[rand], array[i]]
}
}
ES6 Чистий, ітеративний
const getShuffledArr = arr => {
const newArr = arr.slice()
for (let i = newArr.length - 1; i > 0; i--) {
const rand = Math.floor(Math.random() * (i + 1));
[newArr[i], newArr[rand]] = [newArr[rand], newArr[i]];
}
return newArr
};
Як ви бачите на цій сторінці, тут раніше було запропоновано неправильні рішення. Я написав і використав наступну функцію для перевірки будь-яких чистих (без побічних ефектів) масивів рандомізуючих функцій.
function testShuffleArrayFun(getShuffledArrayFun){
const arr = [0,1,2,3,4,5,6,7,8,9]
var countArr = arr.map(el=>{
return arr.map(
el=> 0
)
}) // For each possible position in the shuffledArr and for
// each possible value, we'll create a counter.
const t0 = performance.now()
const n = 1000000
for (var i=0 ; i<n ; i++){
// We'll call getShuffledArrayFun n times.
// And for each iteration, we'll increment the counter.
var shuffledArr = getShuffledArrayFun(arr)
shuffledArr.forEach(
(value,key)=>{countArr[key][value]++}
)
}
const t1 = performance.now()
console.log(`Count Values in position`)
console.table(countArr)
const frequencyArr = countArr.map( positionArr => (
positionArr.map(
count => count/n
)
))
console.log("Frequency of value in position")
console.table(frequencyArr)
console.log(`total time: ${t1-t0}`)
}
Інші рішення просто для задоволення.
ES6 Чистий, рекурсивний
const getShuffledArr = arr => {
if (arr.length === 1) {return arr};
const rand = Math.floor(Math.random() * arr.length);
return [arr[rand], ...getShuffledArr(arr.filter((_, i) => i != rand))];
};
ES6 Pure за допомогою array.map
function getShuffledArr (arr){
return [...arr].map( (_, i, arrCopy) => {
var rand = i + ( Math.floor( Math.random() * (arrCopy.length - i) ) );
[arrCopy[rand], arrCopy[i]] = [arrCopy[i], arrCopy[rand]]
return arrCopy[i]
})
}
ES6 Pure за допомогою array.reduce
function getShuffledArr (arr){
return arr.reduce(
(newArr, _, i) => {
var rand = i + ( Math.floor( Math.random() * (newArr.length - i) ) );
[newArr[rand], newArr[i]] = [newArr[i], newArr[rand]]
return newArr
}, [...arr]
)
}
[array[i], array[rand]]=[array[rand], array[i]]
? Можливо, ви зможете окреслити, як це працює. Чому ви вирішили повторити вниз?
Додавання до @Laurens Холст відповіді. Це на 50% стиснене.
function shuffleArray(d) {
for (var c = d.length - 1; c > 0; c--) {
var b = Math.floor(Math.random() * (c + 1));
var a = d[c];
d[c] = d[b];
d[b] = a;
}
return d
};
var b =
в циклі, а не оголошувати b зовнішньої петлі та призначати її b =
циклу?
Дивіться https://stackoverflow.com/a/18650169/28234 . Тут його залишають для довідки, оскільки ідея не рідкість.
//one line solution
shuffle = (array) => array.sort(() => Math.random() - 0.5);
//Demo
let arr = [1, 2, 3];
shuffle(arr);
alert(arr);
https://javascript.info/task/shuffle
Math.random() - 0.5
- випадкове число, яке може бути позитивним чи негативним, тому функція сортування переставляє елементи випадковим чином.
З ES2015 ви можете використовувати цей:
Array.prototype.shuffle = function() {
let m = this.length, i;
while (m) {
i = (Math.random() * m--) >>> 0;
[this[m], this[i]] = [this[i], this[m]]
}
return this;
}
Використання:
[1, 2, 3, 4, 5, 6, 7].shuffle();
n >>> 0
замість ~~n
. Індекси масиву можуть бути вище 2³ 2-1.
Я знайшов цей варіант, який висить у відповідях "видалений автором" на дублікат цього питання. На відміну від деяких інших відповідей, які вже мають багато результатів, це:
shuffled
а не назва shuffle
)Ось jsfiddle, що показує це у використанні .
Array.prototype.shuffled = function() {
return this.map(function(n){ return [Math.random(), n] })
.sort().map(function(n){ return n[1] });
}
[1,2,3,4,5,6].sort(function() { return .5 - Math.random(); });
- це не дає випадкового сортування, і якщо ви використовуєте його, ви можете збентежитися: robweir.com/blog/2010/02/microsoft-random-browser-ballot.html
.sort(function(a,b){ return a[0] - b[0]; })
якщо ви хочете, щоб сортування порівняло значення чисельно. .sort()
Порівняння за замовчуванням є лексикографічним, тобто його вважатимуть 10
меншим, 2
оскільки 1
менше 2
.
Math.random()
виробляє. (тобто лексикографічний порядок - це те саме, що числовий порядок при роботі з числами від 0 (включно) до 1 (виключно))
var shuffle = function(array) {
temp = [];
originalLength = array.length;
for (var i = 0; i < originalLength; i++) {
temp.push(array.splice(Math.floor(Math.random()*array.length),1));
}
return temp;
};
arr1.sort(() => Math.random() - 0.5);
Ви можете легко зробити це за допомогою:
// array
var fruits = ["Banana", "Orange", "Apple", "Mango"];
// random
fruits.sort(function(a, b){return 0.5 - Math.random()});
// out
console.log(fruits);
Будь ласка, зверніться до JavaScript сортування масивів
Фішер-Йейт переміщується в JavaScript. Я розміщую це тут, оскільки використання двох функцій утиліти (swap та randInt) уточнює алгоритм порівняно з іншими відповідями тут.
function swap(arr, i, j) {
// swaps two elements of an array in place
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function randInt(max) {
// returns random integer between 0 and max-1 inclusive.
return Math.floor(Math.random()*max);
}
function shuffle(arr) {
// For each slot in the array (starting at the end),
// pick an element randomly from the unplaced elements and
// place it in the slot, exchanging places with the
// element in the slot.
for(var slot = arr.length - 1; slot > 0; slot--){
var element = randInt(slot+1);
swap(arr, element, slot);
}
}
Перш за все, подивіться тут на велике візуальне порівняння різних методів сортування в JavaScript.
По-друге, якщо ви швидко ознайомитеся з посиланням вище, ви побачите, що random order
сорт, здається, працює порівняно з іншими методами, при цьому надзвичайно легко та швидко реалізувати, як показано нижче:
function shuffle(array) {
var random = array.map(Math.random);
array.sort(function(a, b) {
return random[array.indexOf(a)] - random[array.indexOf(b)];
});
}
Редагувати : як зазначає @gregers, функція порівняння викликається значеннями, а не індексами, саме тому вам потрібно скористатися indexOf
. Зауважте, що ця зміна робить код менш придатним для більших масивів, оскільки вони indexOf
працюють в O (n) час.
Array.prototype.sort
передає два значення як a
і b
, а не індекс. Тож цей код не працює.
Оновлення : Тут я пропоную порівняно простий (не з точки зору складності ) та короткий алгоритм, який буде спрацьовувати добре з масивами невеликих розмірів, але це, безумовно, коштуватиме набагато дорожче, ніж класичний алгоритм Дюрстенфельда , коли ви маєте справу з величезними масивами. Ви можете знайти Дурстенфельд в одній з найкращих відповідей на це запитання.
Оригінальна відповідь:
Якщо ви не бажаєте, щоб ваша функція перетасування мутавала вихідний масив , ви можете скопіювати її в локальну змінну, а потім зробити все за допомогою простої логіки переміщення .
function shuffle(array) {
var result = [], source = array.concat([]);
while (source.length) {
let index = Math.floor(Math.random() * source.length);
result.push(source[index]);
source.splice(index, 1);
}
return result;
}
Логіка переміщення : підберіть випадковий індекс, а потім додайте відповідний елемент до масиву результатів та видаліть його з копії вихідного масиву . Повторіть цю дію, поки вихідний масив не спорожниться .
І якщо ви дійсно хочете цього короткого, ось як далеко я міг би дістатися:
function shuffle(array) {
var result = [], source = array.concat([]);
while (source.length) {
let index = Math.floor(Math.random() * source.length);
result.push(source.splice(index, 1)[0]);
}
return result;
}
splice
жахливо неефективний спосіб зробити те, що вони назвали "викреслити". Якщо ви не хочете мутувати вихідний масив, просто скопіюйте його та перетасуйте цю копію на місці, використовуючи набагато ефективніший варіант Дюрстенфельда.
splice
метод , щоб створити копію наступним чином: source = array.slice();
.
Ось найпростіший ,
function shuffle(array) {
array.sort(() => Math.random() - 0.5);
}
для подальшого прикладу ви можете перевірити це тут
ще одна реалізація Fisher-Yates з використанням суворого режиму:
function shuffleArray(a) {
"use strict";
var i, t, j;
for (i = a.length - 1; i > 0; i -= 1) {
t = a[i];
j = Math.floor(Math.random() * (i + 1));
a[i] = a[j];
a[j] = t;
}
return a;
}
Всі інші відповіді базуються на Math.random (), який є швидким, але не підходить для рандомізації криптографічного рівня.
Наведений нижче код використовує добре відомий Fisher-Yates
алгоритм при використанні Web Cryptography API
для криптографічного рівня рандомізації .
var d = [1,2,3,4,5,6,7,8,9,10];
function shuffle(a) {
var x, t, r = new Uint32Array(1);
for (var i = 0, c = a.length - 1, m = a.length; i < c; i++, m--) {
crypto.getRandomValues(r);
x = Math.floor(r / 65536 / 65536 * m) + i;
t = a [i], a [i] = a [x], a [x] = t;
}
return a;
}
console.log(shuffle(d));
Проста модифікація CoolAJ86 в відповідь , що не змінює вихідний масив:
/**
* Returns a new array whose contents are a shuffled copy of the original array.
* @param {Array} The items to shuffle.
* https://stackoverflow.com/a/2450976/1673761
* https://stackoverflow.com/a/44071316/1673761
*/
const shuffle = (array) => {
let currentIndex = array.length;
let temporaryValue;
let randomIndex;
const newArray = array.slice();
// While there remains elements to shuffle...
while (currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// Swap it with the current element.
temporaryValue = newArray[currentIndex];
newArray[currentIndex] = newArray[randomIndex];
newArray[randomIndex] = temporaryValue;
}
return newArray;
};
Хоча існує ряд реалізованих реалізацій, але я вважаю, що ми можемо скоротити та простіше використовувати цикл forEach, тому нам не потрібно турбуватися про обчислення довжини масиву, а також ми можемо безпечно уникати використання тимчасової змінної.
var myArr = ["a", "b", "c", "d"];
myArr.forEach((val, key) => {
randomIndex = Math.ceil(Math.random()*(key + 1));
myArr[key] = myArr[randomIndex];
myArr[randomIndex] = val;
});
// see the values
console.log('Shuffled Array: ', myArr)
Просто мати палець у пирозі. Тут я представляю рекурсивну реалізацію перекладу Фішера Йейта (я думаю). Це дає рівномірну випадковість.
Примітка: ~~
(оператор подвійного тильду) насправді веде себе як Math.floor()
для позитивних дійсних чисел. Просто скорочення це.
var shuffle = a => a.length ? a.splice(~~(Math.random()*a.length),1).concat(shuffle(a))
: a;
console.log(JSON.stringify(shuffle([0,1,2,3,4,5,6,7,8,9])));
Редагувати: вищевказаний код є O (n ^ 2) завдяки використанню, .splice()
але ми можемо усунути сплайсинг і переміщення в O (n) методом swap.
var shuffle = (a, l = a.length, r = ~~(Math.random()*l)) => l ? ([a[r],a[l-1]] = [a[l-1],a[r]], shuffle(a, l-1))
: a;
var arr = Array.from({length:3000}, (_,i) => i);
console.time("shuffle");
shuffle(arr);
console.timeEnd("shuffle");
Проблема в тому, що JS не може впоратися з великими рекурсіями. У цьому конкретному випадку розмір масиву обмежений приблизно 3000 ~ 7000 залежно від двигуна браузера та деяких невідомих фактів.
Довільний масив
var arr = ['apple','cat','Adam','123','Zorro','petunia'];
var n = arr.length; var tempArr = [];
for ( var i = 0; i < n-1; i++ ) {
// The following line removes one random element from arr
// and pushes it onto tempArr
tempArr.push(arr.splice(Math.floor(Math.random()*arr.length),1)[0]);
}
// Push the remaining item onto tempArr
tempArr.push(arr[0]);
arr=tempArr;
-1
для росіян, як ви звикли, <
не<=
найкоротша arrayShuffle
функція
function arrayShuffle(o) {
for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
}
З теоретичної точки зору, найелегантніший спосіб зробити це, на мою скромну думку, - отримати єдине випадкове число між 0 і n! -1 і обчислити відображення від одного до одного {0, 1, …, n!-1}
для всіх перестановок (0, 1, 2, …, n-1)
. Поки ви можете використовувати (псевдо-) випадковий генератор, достатньо надійний для отримання такого числа без будь-якого істотного зміщення, у вас є в ньому достатньо інформації для досягнення того, що ви хочете, не потребуючи кількох інших випадкових чисел.
Обчислюючи плаваючі числа з подвійною точністю IEEE754, ви можете розраховувати, що ваш випадковий генератор надасть близько 15 десяткових знаків. Оскільки у вас 15! = 1,307,674,368,000 (з 13 цифрами), ви можете використовувати наступні функції з масивами, що містять до 15 елементів, і припускати, що з масивами, що містять до 14 елементів, не буде суттєвого зміщення. Якщо ви працюєте над проблемою фіксованого розміру, яка вимагає багаторазово обчислити цю операцію переміщення, ви можете спробувати наступний код, який може бути швидшим, ніж інші коди, оскільки він використовується Math.random
лише один раз (проте він включає кілька операцій копіювання).
Наступна функція не буде використовуватися, але я її надаю; він повертає індекс заданої перестановки (0, 1, 2, …, n-1)
відповідно до відображення від одного до одного, яке використовується в цьому повідомленні (найбільш природне при перерахуванні перестановок); призначений для роботи з до 16 елементами:
function permIndex(p) {
var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000];
var tail = [];
var i;
if (p.length == 0) return 0;
for(i=1;i<(p.length);i++) {
if (p[i] > p[0]) tail.push(p[i]-1);
else tail.push(p[i]);
}
return p[0] * fact[p.length-1] + permIndex(tail);
}
Взаємність попередньої функції (необхідна для вашого власного запитання) нижче; призначений для роботи з до 16 елементами; вона повертає перестановку порядку п з (0, 1, 2, …, s-1)
:
function permNth(n, s) {
var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000];
var i, j;
var p = [];
var q = [];
for(i=0;i<s;i++) p.push(i);
for(i=s-1; i>=0; i--) {
j = Math.floor(n / fact[i]);
n -= j*fact[i];
q.push(p[j]);
for(;j<i;j++) p[j]=p[j+1];
}
return q;
}
Тепер, що ви просто хочете, це:
function shuffle(p) {
var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000];
return permNth(Math.floor(Math.random()*fact[p.length]), p.length).map(
function(i) { return p[i]; });
}
Він повинен працювати до 16 елементів з невеликим теоретичним ухилом (хоча і непомітний з практичної точки зору); її можна вважати цілком придатною для використання в 15 елементах; з масивами, що містять менше 14 елементів, ви можете сміливо вважати, що упереджень абсолютно не буде.