Jak losować (shuffle) tablicę JavaScript?

Mam taką tablicę:

var arr1 = ["a", "b", "c", "d"];

Jak mogę losować / tasować?

Author: Nit, 2010-03-16

30 answers

De facto bezstronny algorytm shuffle jest Fisher-Yates (aka Knuth) Shuffle.

Zobacz https://github.com/coolaj86/knuth-shuffle

Możesz zobaczyć wielką wizualizację tutaj (i oryginalny post połączony z tym)

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];
arr = shuffle(arr);
console.log(arr);

Trochę więcej informacji o zastosowanym algorytmie .

 1141
Author: CoolAJ86,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-11 04:18:38

Jest to implementacja JavaScript durstenfeld shuffle, zoptymalizowanej komputerowo wersji Fisher-Yates:

/**
 * Randomize array element order 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;
    }
}
Algorytm Fisher-Yates działa poprzez wybranie jednego losowego elementu dla każdego oryginalnego elementu tablicy, a następnie wykluczenie go z następnego losowania. Zupełnie jak losowe wybieranie z talii kart.

To wykluczenie odbywa się w sprytny sposób (wymyślony przez Durstenfelda do użytku przez komputery) poprzez zamianę wybranego elementu na bieżący element, a następnie wybierając kolejny losowy element z reszty. Dla optymalnej wydajności pętla biegnie do tyłu, dzięki czemu losowy pick jest uproszczony (zawsze może zaczynać się od 0) i pomija ostatni element, ponieważ nie ma już innych opcji.

Czas działania tego algorytmu wynosi O (n). Należy pamiętać, że tasowanie odbywa się na miejscu. Jeśli więc nie chcesz modyfikować oryginalnej tablicy, najpierw zrób jej kopię za pomocą .slice(0).

Aktualizacja do ES6 / ECMAScript 2015

Nowy ES6 pozwala nam przypisać dwie zmienne jednocześnie. Jest to szczególnie przydatne, gdy chcemy zamienić wartości dwóch zmiennych, ponieważ możemy to zrobić w jednej linii kodu. Oto krótsza forma tej samej funkcji, wykorzystująca tę funkcję.

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]]; // eslint-disable-line no-param-reassign
    }
}
 502
Author: Laurens Holst,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-15 14:40:36

[edycja społeczności: ta odpowiedź jest nieprawidłowa; Zobacz komentarze. Zostawia się go tutaj do przyszłego odniesienia, ponieważ pomysł nie jest tak rzadki.]

[1,2,3,4,5,6].sort(function() {
  return .5 - Math.random();
});
 89
Author: deadrunk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-22 22:19:57

Można (lub powinno) używać go jako prototype z tablicy:

From:

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;
}
 68
Author: con,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-16 02:53:06

Użyj podkreślenia.biblioteka js. Metoda _.shuffle() jest dobra w tym przypadku. Oto przykład metody:

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();
 56
Author: vn_grv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-12 03:05:51

Nowość!

Shorter & probably *faster Fisher-Yates shuffle algorithm

  1. używa while - - -
  2. bitowo do podłogi (liczby do 10 cyfr dziesiętnych (32bit))
  3. usunięte niepotrzebne zamknięcia i inne rzeczy

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
}

Rozmiar skryptu (z fy jako nazwą funkcji): 90bytes

DEMO http://jsfiddle.net/vvpoma8w/

*szybciej chyba we wszystkich przeglądarkach oprócz chrome.

Jeśli masz jakieś pytania po prostu pytaj.

EDIT

Yes it is faster

Osiągi: http://jsperf.com/fyshuffle

Korzystanie z topowych funkcji.

EDIT Nie było obliczenia w nadmiarze (nie trzeba --c+1) i nikt nie zauważył

Shorter (4bytes)&faster (test it!).

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
}

Buforowanie gdzie indziej var rnd=Math.random a następnie użycie rnd() również zwiększyłoby nieco wydajność na dużych tablice.

Http://jsfiddle.net/vvpoma8w/2/

Wersja czytelna (użyj wersji oryginalnej. jest to wolniejsze, vary są bezużyteczne, podobnie jak zamknięcia&";", sam kod jest również krótszy ... może przeczytaj to jak "minify" kod Javascript , btw nie jesteś w stanie skompresować poniższego kodu w minifierze javascript, takim jak powyższy.)

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
 }
}
 45
Author: cocco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:44

Możesz to zrobić łatwo za pomocą mapy i sortowania:

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)
  1. umieszczamy każdy element w tablicy w obiekcie i nadajemy mu losowy klucz sortowania
  2. sortujemy za pomocą Losowego klucza
  3. unmap, aby uzyskać oryginalne obiekty

Możesz przetasować tablice polimorficzne, a sortowanie jest tak losowe, jak matematyka.przypadkowy, który jest wystarczająco dobry dla większości celów.

Ponieważ elementy są sortowane według spójnych kluczy, które nie są regenerowane w każdej iteracji, a każde porównanie ciągnie z tego samego rozkładu, Dowolna nie przypadkowość w rozkładzie matematyki.losowe jest anulowane.

 33
Author: superluminary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-03 11:39:15

Bardzo prosty sposób dla małych tablic jest po prostu taki:

const someArray = [1, 2, 3, 4, 5];

someArray.sort(() => Math.random() - 0.5);

Prawdopodobnie nie jest to zbyt wydajne, ale w przypadku małych tablic działa to dobrze. Oto przykład, dzięki któremu możesz zobaczyć, jak losowy (lub nie) jest on i czy pasuje do twojej bazy użytkowników, czy nie.

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>
 25
Author: Kris Selbekk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-17 14:01:14

Dodawanie do @Laurens Holsts odpowiedz. To jest w 50% skompresowane.

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
};
 19
Author: KingKongFrog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-12 03:04:31

Z ES2015 możesz użyć tego:

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;
}

Użycie:

[1, 2, 3, 4, 5, 6, 7].shuffle();
 14
Author: BrunoLM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-24 04:26:13
var shuffle = function(array) {
   temp = [];
   for (var i = 0; i < array.length ; i++) {
     temp.push(array.splice(Math.floor(Math.random()*array.length),1));
   }
   return temp;
};
 13
Author: Tophe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-12 03:02:36

Znalazłem ten wariant wiszący w odpowiedziach "deleted by author" na duplikacie tego pytania. W przeciwieństwie do innych odpowiedzi, które mają już wiele głosów, jest to:

  1. właściwie random
  2. nie na miejscu (stąd nazwa {[1] } a nie shuffle)
  3. nie występuje już tutaj z wieloma wariantami

Oto jsfiddle pokazujący go w użyciu .

Array.prototype.shuffled = function() {
  return this.map(function(n){ return [Math.random(), n] })
             .sort().map(function(n){ return n[1] });
}
 12
Author: Daniel Martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-10 14:56:58

Rozwiązanie rekurencyjne:

function shuffle(a,b){
    return a.length==0?b:function(c){
        return shuffle(a,(b||[]).concat(c));
    }(a.splice(Math.floor(Math.random()*a.length),1));
};
 8
Author: Julian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-26 08:40:01

Z ES6, 2018

Niektóre odpowiedzi można skrócić za pomocą najnowszego ES6.

Shuffle Array In place

function shuffleArray (array){
    for (let i = array.length - 1; i > 0; i--) {
        const rand = Math.floor(Math.random() * (i + 1));
        [array[i], array[rand]] = [array[rand], array[i]];
    }
}

Za pomocą ES6 możemy przypisać dwie wartości jednocześnie. Jest to szczególnie przydatne w linii 4 powyżej, gdzie dwie zmienne są zamieniane w jednym wierszu kodu.

Pozostaw oryginalną tablicę nienaruszoną i zwróć tablicę tasowaną

Jeśli chcesz stworzyć bardziej czystą funkcję i pozostawić oryginalną tablicę nienaruszoną, możesz po prostu powielić tablicę, a następnie uruchomić tę samą algorytm.

function getShuffledArray (arr){
    let newArr = [...arr]
    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;
}

Algorytm rosnący

Poniższy algorytm wykorzystuje pętlę wstępującą. Jest mniej intuicyjny, ale krótki i ważny.

function getShuffledArrayAsc (arr){
    let newArr = [...arr];
    for (let i = 1; i < newArr.length ; i++) {
        const rand = Math.floor( Math.random() * (i + 1) ); 
        [newArr[i], newArr[rand]] = [newArr[rand], newArr[i]];
    }
    return newArr;
}

Sprawdzanie niezawodności funkcji Randomizującej

Powyższe funkcje prezentowały równomierny rozkład po przekazaniu do' testShuffledArrayFun ' poniżej, zarówno w Chrome, jak i w Node. Jest to zgodne z tym, czego oczekiwalibyśmy od funkcji randomizującej.

function testShuffledArrayFun(getShuffledArrayFun){
    // Tests the reliability of the suffleArrayFunction, by callying it 1,000 times and presenting the distribution. 
    const testArr = [0,1,2,3,4];
    const countArr = testArr.map( position => // for for each possible position in the shuffledArr, for each possible value, we'll create a counter. the counter of value 0 in position 0 will be countArr[0][0]
        testArr.map( value => 0)  
    )

    const n = 10000;
    for (var i=0 ; i<n ; i++){
        // We'll call getShuffledArrayFun for n times. For each shuffledArray we receive we'll increment the counterArr accordingly. At the end we'll print the distribution.
        var shuffledArr = getShuffledArrayFun(testArr);
        shuffledArr.forEach(
            (value, key) => {countArr[key][value]++}
        );
    }

    countArr.forEach(
        (valueCountArr,key) => {
            console.log(`Position ${key}:`);
            valueCountArr.forEach(
                (count,originalValue) => {
                    console.log(`The Value ${originalValue} appeared ${count*100/n}% `);
                }
            );
        }
    );
}
 8
Author: Ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-22 04:09:58

Fisher-Yates shuffle w javascript. Zamieszczam to tutaj, ponieważ użycie dwóch funkcji użytkowych (swap i randInt) wyjaśnia algorytm w porównaniu z innymi odpowiedziami tutaj.

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);
  }
}
 7
Author: dpatru,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-01 01:53:39

Po pierwsze, spójrz tutaj, aby uzyskać świetne wizualne porównanie różnych metod sortowania w javascript.

Po drugie, jeśli spojrzysz na powyższy link, przekonasz się, że sortowanie random order wydaje się działać stosunkowo dobrze w porównaniu do innych metod, a jednocześnie jest niezwykle łatwe i szybkie w implementacji, jak pokazano poniżej:

function shuffle(array) {
  var random = array.map(Math.random);
  array.sort(function(a, b) {
    return random[array.indexOf(a)] - random[array.indexOf(b)];
  });
}

Edit: jak zauważył @gregers, funkcja compare jest wywoływana z wartościami, a nie indeksami, dlatego potrzebujesz aby użyć indexOf. Zauważ, że ta zmiana sprawia, że kod jest mniej odpowiedni dla większych tablic, ponieważ indexOf działa w czasie O (n).

 7
Author: 0sh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-15 15:00:11

Kolejna implementacja Fishera-Yatesa, używająca trybu ścisłego:

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;
}
 5
Author: Raphael C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-21 13:20:28

Możesz to zrobić łatwo z:

// array
var fruits = ["Banana", "Orange", "Apple", "Mango"];
// random
fruits.sort(function(a, b){return 0.5 - Math.random()});
// out
console.log(fruits);

Proszę odnieść się do JavaScript sortowanie tablic

 5
Author: TinhNQ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-20 06:59:22

Funkcja shuffle, która nie zmienia tablicy źródłowej

Update : tutaj sugeruję stosunkowo prosty (nie z perspektywy złożoność) i krótkialgorytm, który sprawdzi się w przypadku małych tablic, ale na pewno będzie kosztować znacznie więcej niż klasyczny algorytm Durstenfelda , Gdy masz do czynienia z dużymi tablicami. Możesz znaleźć Durstenfeld w jednej z najlepszych odpowiedzi na to pytanie.

oryginał ODPOWIEDŹ:

Jeśli nie chcesz, aby twoja funkcja shuffle zmutowała tablicę źródłową, możesz skopiować ją do zmiennej lokalnej, a następnie wykonać resztę za pomocą prostej logiki tasowania.

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;
}

tasowanie logiki: pobranie losowego indeksu, następnie dodanie odpowiedniego elementu do tablicy wyników i usunięcie go z kopii tablicy źródłowej . Powtórz tę czynność, aż tablica źródłowa zostanie pusta .

I jeśli naprawdę tego chcesz krótko, oto jak daleko mogłem się dostać:

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;
}
 5
Author: Evgenia Manolova,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-20 11:08:18

Wszystkie pozostałe odpowiedzi są oparte na matematyce.random (), która jest szybka, ale nie nadaje się do randomizacji na poziomie kryptograficznym.

Poniższy kod wykorzystuje dobrze znany algorytm Fisher-Yates, wykorzystując Web Cryptography API dla kryptograficznego poziomu randomizacji .

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));
 4
Author: Marcin Malinowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-23 21:33:39

Żeby mieć palec w cieście. Tutaj przedstawiam rekurencyjną implementację Fisher Yates shuffle (tak myślę). Daje jednolitą przypadkowość.

Uwaga: ~~ (operator podwójnej tyldy) w rzeczywistości zachowuje się jak Math.floor() dla dodatnich liczb rzeczywistych. To tylko skrót.

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])));
 4
Author: Redu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-20 08:08:18

Chociaż jest już wiele implementacji, ale czuję, że możemy to skrócić i ułatwić za pomocą pętli forEach, więc nie musimy się martwić o obliczanie długości tablicy, a także możemy bezpiecznie uniknąć użycia zmiennej tymczasowej.

var arr1 = ["a", "b", "c", "d"];

arr1.forEach((val, key) => {
  randomIndex = Math.ceil(Math.random()*(key + 1));
  arr1[key] = arr1[randomIndex];
  arr1[randomIndex] = val;
});
 4
Author: Hafizur Rahman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-07 11:25:58

Najkrótsza arrayShuffle Funkcja

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;
}
 3
Author: Tusko Trush,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-17 18:13:49

Z teoretycznego punktu widzenia, najbardziej eleganckim sposobem, moim skromnym zdaniem, jest uzyskanie pojedynczej losowej liczby pomiędzy 0 i n!-1 i obliczyć odwzorowanie jeden do jednego z {0, 1, …, n!-1} dla wszystkich permutacji (0, 1, 2, …, n-1). Tak długo, jak możesz użyć (pseudo)generatora losowego wystarczająco niezawodnego, aby uzyskać taką liczbę bez żadnego znaczącego uprzedzenia, masz w nim wystarczająco dużo informacji, aby osiągnąć to, czego chcesz, bez potrzeby kilku innych losowych liczby.

Podczas obliczania liczb zmiennoprzecinkowych z podwójną precyzją IEEE754, można oczekiwać, że generator losowy dostarczy około 15 miejsc po przecinku. Ponieważ masz 15!=1,307,674,368,000 (z 13 cyframi), można używać następujących funkcji z tablicami zawierającymi do 15 elementów i zakładać, że nie będzie znaczącego błędu przy tablicach zawierających do 14 elementów. Jeśli pracujesz nad problemem o stałym rozmiarze wymagającym wielokrotnego obliczania tej operacji shuffle, możesz spróbować po kodzie, który może być szybszy od innych kodów, ponieważ używa Math.random tylko raz (wymaga jednak kilku operacji kopiowania).

Następująca funkcja nie zostanie użyta, ale i tak ją podaję; zwraca indeks danej permutacji (0, 1, 2, …, n-1) zgodnie z mapowaniem jeden do jednego używanym w tej wiadomości (najbardziej naturalnym przy wyliczaniu permutacji); jest przeznaczona do pracy z maksymalnie 16 elementami:

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);
}

Odwrotność poprzedniej funkcji (wymagana dla Twoje własne pytanie) znajduje się poniżej; jest przeznaczony do pracy z maksymalnie 16 elementami; zwraca permutację rzędu n z (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;
}

Teraz, co chcesz tylko jest:

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]; });
}

Powinien działać dla maksymalnie 16 elementów z niewielkim teoretycznym odchyleniem (choć niezauważalnym z praktycznego punktu widzenia); może być postrzegany jako w pełni użyteczny dla 15 elementów; z tablicami zawierającymi mniej niż 14 elementów, można bezpiecznie rozważyć, że nie będzie żadnego odchylenia.

 3
Author: Thomas Baruchel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-25 07:41:05

Nowoczesne Krótkie rozwiązanie inline wykorzystujące funkcje ES6:

['a','b','c','d'].map(x => [Math.random(), x]).sort(([a], [b]) => a - b).map(([_, x]) => x);

(dla celów edukacyjnych)

 3
Author: icl7126,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-15 18:14:29

Prosta modyfikacja odpowiedzi CoolAJ86 które nie modyfikują oryginalnej tablicy

 /**
 * Returns a new array whose contents are a copy shuffled of the array.
 * @param {Array} a 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 remain elements to shuffle...
  while (currentIndex) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;
    // And swap it with the current element.
    temporaryValue = newArray[currentIndex];
    newArray[currentIndex] = newArray[randomIndex];
    newArray[randomIndex] = temporaryValue;
  }
  return newArray;
};
 3
Author: abumalick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-20 07:06:21
Array.prototype.shuffle=function(){
   var len = this.length,temp,i
   while(len){
    i=Math.random()*len-- |0;
    temp=this[len],this[len]=this[i],this[i]=temp;
   }
   return this;
}
 2
Author: user1289673,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-21 06:31:07

Randomize array using array.splice ()

function shuffleArray(array) {
   var temp = [];
   var len=array.length;
   while(len){
      temp.push(array.splice(Math.floor(Math.random()*array.length),1)[0]);
      len--;
   }
   return temp;
}
//console.log("Here >>> "+shuffleArray([4,2,3,5,8,1,0]));

Demo

 2
Author: Saravanan Rajaraman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-27 15:51:32

Randomize array

 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; 
 2
Author: vickisys,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-07 07:51:52
var shuffledArray = function(inpArr){
    //inpArr - is input array
    var arrRand = []; //this will give shuffled array
    var arrTempInd = []; // to store shuffled indexes
    var max = inpArr.length;
    var min = 0;
    var tempInd;
    var i = 0;

    do{
        //generate random index between range
        tempInd = Math.floor(Math.random() * (max - min));
        //check if index is already available in array to avoid repetition
        if(arrTempInd.indexOf(tempInd)<0){
            //push character at random index
            arrRand[i] = inpArr[tempInd];
            //push random indexes
            arrTempInd.push(tempInd);
            i++;
        }
    }
    // check if random array length is equal to input array length
    while(arrTempInd.length < max){
        return arrRand; // this will return shuffled Array
    }
};

Po prostu przekaż tablicę do funkcji i w zamian uzyskaj tablicę tasowaną

 2
Author: Mayur Nandane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-23 03:47:00