J'ai un tableau comme celui-ci:
var arr1 = ["a", "b", "c", "d"];
Comment puis-je randomiser/mélanger?
L'algorithme de mélange impartial de facto est le Fisher-Yates (aka Knuth) Shuffle.
Voir https://github.com/coolaj86/knuth-shuffle
Vous pouvez voir une grande visualisation ici (et le message original lié à cela )
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);
Quelques informations supplémentaires sur l’algorithme utilisé.
Voici une implémentation JavaScript de Durstenfeld shuffle , une version optimisée par ordinateur de 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;
}
}
L'algorithme de Fisher-Yates fonctionne en choisissant un élément aléatoire pour chaque élément de tableau d'origine, puis en l'excluant du prochain tirage. Tout comme choisir au hasard dans un jeu de cartes.
Cette exclusion est faite de manière intelligente (inventée par Durstenfeld pour être utilisée par des ordinateurs) en échangeant l’élément sélectionné avec l’élément actuel, puis en sélectionnant l’élément aléatoire suivant dans le reste. Pour une efficacité optimale, la boucle fonctionne à l'envers, ce qui simplifie la sélection aléatoire (elle peut toujours commencer à 0) et ignore le dernier élément car il n'y a plus d'autre choix.
Le temps d'exécution de cet algorithme est O (n). Notez que le shuffle est fait sur place. Donc, si vous ne voulez pas modifier le tableau d'origine, faites-en une copie d'abord avec .slice(0)
.
La nouvelle ES6 nous permet d’attribuer deux variables à la fois. Ceci est particulièrement utile lorsque nous voulons échanger les valeurs de deux variables, car nous pouvons le faire dans une ligne de code. Voici une forme plus courte de la même fonction, en utilisant cette fonctionnalité.
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]];
}
}
[communauté edit: Cette réponse est incorrecte; voir les commentaires. Il est laissé ici pour référence future car l’idée n’est pas si rare.]
[1,2,3,4,5,6].sort(function() {
return .5 - Math.random();
});
On pourrait (ou devrait) l’utiliser comme prototype de Array:
De ChristopheR:
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;
}
Utilisez la bibliothèque underscore.js. La méthode _.shuffle()
est agréable pour ce cas . Voici un exemple avec la méthode:
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();
NOUVEAU!
Plus court et probablement * plus rapide algorithme de lecture aléatoire 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
}
taille du script (avec fy comme nom de la fonction): 90 octets
D&EACUTE;MOhttp://jsfiddle.net/vvpoma8w/
* plus rapide probablement sur tous les navigateurs sauf chrome.
Si vous avez des questions, vous avez juste à me les poser.
MODIFIER
oui c'est plus rapide
PERFORMANCE: _ http://jsperf.com/fyshuffle
en utilisant les fonctions les plus votées.
EDIT Il y avait un calcul en excès (pas besoin de --c + 1) et personne n'a remarqué
plus court (4 octets) et plus rapide (testez-le!).
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
}
Mettre en cache quelque chose d'autre var rnd=Math.random
et ensuite utiliser rnd()
augmenterait également légèrement les performances sur les grands tableaux.
http://jsfiddle.net/vvpoma8w/2/
Version lisible (utilisez la version originale. C'est plus lent, les vars sont inutiles, comme les fermetures & ";", le code lui-même est aussi plus court ... lisez peut-être ceci Comment "minifier" le code Javascript }, vous ne pouvez pas compresser le code suivant dans un code javascript comme celui ci-dessus.)
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
}
}
Vous pouvez le faire facilement avec carte et trier:
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)
Vous pouvez mélanger des tableaux polymorphes et le type est aussi aléatoire que Math.random, ce qui est suffisant pour la plupart des applications.
Étant donné que les éléments sont triés en fonction de clés cohérentes qui ne sont pas régénérées à chaque itération et que chaque comparaison est extraite de la même distribution, tout caractère non aléatoire de la distribution de Math.random est annulé.
Voici un moyen très simple pour les petits tableaux:
const someArray = [1, 2, 3, 4, 5];
someArray.sort(() => Math.random() - 0.5);
Ce n'est probablement pas très efficace, mais cela fonctionne très bien pour les petits tableaux. Voici un exemple pour que vous puissiez voir si c'est aléatoire (ou non) et si cela convient à votre cas d'utilisation ou non.
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>
Ajouter à la réponse de @Laurens Holsts. C'est compressé à 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
};
Avec ES2015, vous pouvez utiliser celui-ci:
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;
}
Usage:
[1, 2, 3, 4, 5, 6, 7].shuffle();
Certaines réponses pourraient être abrégées à l'aide de la syntaxe 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
};
Personnellement, j'utilise cette fonction car elle est pure, relativement simple et, d'après mes tests sur Google Chrome, la plus efficace (par rapport à d'autres versions pures).
function getShuffledArr (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]]
}
}
Comme vous pouvez le voir sur cette page, des solutions incorrectes ont été proposées ici par le passé. Ainsi, dans un souci de fiabilité et de performance, j’ai écrit la fonction suivante pour tester toutes les fonctions de randomisation de tableaux pures (sans effets secondaires). Je l'ai utilisé pour tester toutes les options présentées dans cette réponse.
function testShuffledArrayFun(getShuffledArrayFun){
const arr = [0,1,2,3,4,5,6,7,8,9]
let 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 (let i=0 ; i<n ; i++){
// We'll call getShuffledArrayFun n times.
// And for each iteration, we'll increment the counter.
const 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}`)
}
Vous pouvez utiliser l'un des éléments suivants.
type GetShuffledArr= <T>(arr:Array<T>) => Array<T>
interface IGetShuffledArr{
<T>(arr:Array<T>): Array<T>
}
ES6 Pure, récursive
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))];
};
Cette version est moins efficace que la version pure itérative.
ES6 Pure using 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]
})
}
Cette version est légèrement moins efficace que la version pure itérative.
ES6 Pure using 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]
)
}
Cette version est légèrement moins efficace que la version pure itérative.
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;
};
J'ai trouvé cette variante dans les réponses "supprimé par l'auteur" sur un duplicata de cette question. Contrairement à certaines des autres réponses qui ont déjà reçu beaucoup de votes positifs, voici ce qui suit:
shuffled
plutôt que shuffle
)Voici un jsfiddle montrant qu'il est utilisé .
Array.prototype.shuffled = function() {
return this.map(function(n){ return [Math.random(), n] })
.sort().map(function(n){ return n[1] });
}
Une solution récursive:
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));
};
Fisher-Yates shuffle en javascript. Je poste ceci ici parce que l'utilisation de deux fonctions utilitaires (swap et randInt) clarifie l'algorithme par rapport aux autres réponses ici.
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);
}
}
Vous pouvez le faire facilement avec:
// array
var fruits = ["Banana", "Orange", "Apple", "Mango"];
// random
fruits.sort(function(a, b){return 0.5 - Math.random()});
// out
console.log(fruits);
Veuillez faire référence à JavaScript Sorting Arrays
Tout d’abord, regardez ici pour une comparaison visuelle des différentes méthodes de tri en javascript.
Deuxièmement, si vous jetez un coup d'œil au lien ci-dessus, vous constaterez que le type random order
semble fonctionner relativement bien comparé aux autres méthodes, tout en étant extrêmement facile et rapide à mettre en œuvre, comme indiqué ci-dessous:
function shuffle(array) {
var random = array.map(Math.random);
array.sort(function(a, b) {
return random[array.indexOf(a)] - random[array.indexOf(b)];
});
}
Edit: comme l'a souligné @gregers, la fonction de comparaison est appelée avec des valeurs plutôt que des indices, c'est pourquoi vous devez utiliser indexOf
. Notez que cette modification rend le code moins approprié pour les tableaux de grande taille, car indexOf
est exécuté dans le temps O(n).
encore une autre implémentation de Fisher-Yates, en mode strict:
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;
}
Toutes les autres réponses sont basées sur Math.random (), qui est rapide mais ne convient pas à la randomisation au niveau cryptographique.
Le code ci-dessous utilise l'algorithme bien connu Fisher-Yates
tout en utilisant Web Cryptography API
pour niveau de randomisation cryptographique .
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));
function shuffle(array) {
array.sort(() => Math.random() - 0.5);
}
let arr = [1, 2, 3];
shuffle(arr);
alert(arr);
Juste pour avoir un doigt dans la tarte. Je présente ici une implémentation récursive de shuffle de Fisher Yates (je pense). Cela donne un caractère aléatoire uniforme.
Remarque: Le ~~
(opérateur double tilde) se comporte en fait comme Math.floor()
pour les nombres réels positifs. Juste un raccourci c'est.
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])));
Une simple modification de answer de CoolAJ86 qui ne modifie pas le tableau d'origine:
/**
* 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;
};
Un certain nombre d'implémentations sont déjà conseillées, mais je pense que nous pouvons simplifier l'utilisation de la boucle forEach. Nous n'avons donc pas à nous soucier de calculer la longueur d'un tableau et nous pouvons également éviter en toute sécurité d'utiliser une variable temporaire.
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)
Assez drôle, il n'y avait pas de réponse récursive non mutante:
var shuffle = arr => {
const recur = (arr,currentIndex)=>{
console.log("fuck?",JSON.stringify(arr))
if(currentIndex===0){
return arr;
}
const randomIndex = Math.floor(Math.random() * currentIndex);
const swap = arr[currentIndex];
arr[currentIndex] = arr[randomIndex];
arr[randomIndex] = swap;
return recur(
arr,
currentIndex - 1
);
}
return recur(arr.map(x=>x),arr.length-1);
};
var arr = [1,2,3,4,5,[6]];
console.log(shuffle(arr));
console.log(arr);
la plus courte fonction 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;
}
D'un point de vue théorique, la manière la plus élégante de le faire, à mon humble avis, est d'obtenir un nombre unique aléatoire compris entre 0 et n! -1 et de calculer un mappage un à un de {0, 1, …, n!-1}
à toutes les permutations de (0, 1, 2, …, n-1)
. Tant que vous pouvez utiliser un générateur (pseudo) aléatoire suffisamment fiable pour obtenir un tel nombre sans biais significatif, vous avez suffisamment d'informations pour obtenir ce que vous voulez sans avoir besoin de plusieurs autres nombres aléatoires.
Lorsque vous calculez avec des nombres flottants double précision IEEE754, vous pouvez vous attendre à ce que votre générateur aléatoire fournisse environ 15 décimales. Puisque vous avez 15! = 1 307 674 368 000 (avec 13 chiffres), vous pouvez utiliser les fonctions suivantes avec des tableaux contenant jusqu’à 15 éléments et supposer qu’il n’y aura pas de biais significatif avec les tableaux contenant jusqu’à 14 éléments. Si vous travaillez sur un problème de taille fixe nécessitant de calculer plusieurs fois cette opération aléatoire, vous pouvez essayer le code suivant qui peut est plus rapide que d’autres codes car il utilise Math.random
une seule fois (il implique cependant plusieurs opérations de copie. ).
La fonction suivante ne sera pas utilisée, mais je la donne quand même; il renvoie l'indice d'une permutation donnée de (0, 1, 2, …, n-1)
en fonction de la correspondance un à un utilisée dans ce message (la plus naturelle lors de l'énumération des permutations); il est prévu de travailler avec 16 éléments maximum:
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);
}
La réciproque de la fonction précédente (requise pour votre propre question) est ci-dessous; il est prévu de travailler avec 16 éléments maximum; il retourne la permutation d'ordre n de (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;
}
Maintenant, ce que vous voulez simplement, c'est:
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]; });
}
Cela devrait fonctionner pour 16 éléments avec un peu de biais théorique (bien que cela ne se remarque pas d'un point de vue pratique); il peut être considéré comme pleinement utilisable pour 15 éléments; avec des tableaux contenant moins de 14 éléments, vous pouvez sans risque considérer qu’il n’y aura absolument aucun parti pris.
Solution en ligne courte moderne utilisant les fonctionnalités de l'ES6:
['a','b','c','d'].map(x => [Math.random(), x]).sort(([a], [b]) => a - b).map(([_, x]) => x);
(à des fins éducatives)
En utilisant shuffle-array module, vous pouvez mélanger votre tableau. Voici un code simple de celui-ci.
var shuffle = require('shuffle-array'),
//collection = [1,2,3,4,5];
collection = ["a","b","c","d","e"];
shuffle(collection);
console.log(collection);
J'espère que cela t'aides.
Si vous envisagez de l’appliquer à in loco ou à un nouveau tableau immuable, en suivant d’autres solutions, voici une implémentation suggérée:
Array.prototype.shuffle = function(local){
var a = this;
var newArray = typeof local === "boolean" && local ? this : [];
for (var i = 0, newIdx, curr, next; i < a.length; i++){
newIdx = Math.floor(Math.random()*i);
curr = a[i];
next = a[newIdx];
newArray[i] = next;
newArray[newIdx] = curr;
}
return newArray;
};
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;
}
Aléatoire tableau en utilisant 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]));
Au hasard, soit Push ou unshift (ajouter au début).
['a', 'b', 'c', 'd'].reduce((acc, el) => {
Math.random() > 0.5 ? acc.Push(el) : acc.unshift(el);
return acc;
}, []);
Je vois que personne n’a encore donné de solution qui puisse être concaténée sans prolonger le prototype Array (ce qui est une mauvaise pratique ). En utilisant reduce()
légèrement moins connu, nous pouvons facilement mélanger de manière à permettre la concaténation:
var randomsquares = [1, 2, 3, 4, 5, 6, 7].reduce(shuffle).map(n => n*n);
Vous voudrez probablement passer le second paramètre []
, sinon, si vous essayez de faire cela sur un tableau vide, cela échouera:
// Both work. The second one wouldn't have worked as the one above
var randomsquares = [1, 2, 3, 4, 5, 6, 7].reduce(shuffle, []).map(n => n*n);
var randomsquares = [].reduce(shuffle, []).map(n => n*n);
Définissons shuffle
comme:
var shuffle = (Rand, one, i, orig) => {
if (i !== 1) return Rand; // Randomize it only once (arr.length > 1)
// You could use here other random algorithm if you wanted
for (let i = orig.length; i; i--) {
let j = Math.floor(Math.random() * i);
[orig[i - 1], orig[j]] = [orig[j], orig[i - 1]];
}
return orig;
}
Vous pouvez le voir en action dans JSFiddle ou ici:
var shuffle = (all, one, i, orig) => {
if (i !== 1) return all;
// You could use here other random algorithm here
for (let i = orig.length; i; i--) {
let j = Math.floor(Math.random() * i);
[orig[i - 1], orig[j]] = [orig[j], orig[i - 1]];
}
return orig;
}
for (var i = 0; i < 5; i++) {
var randomarray = [1, 2, 3, 4, 5, 6, 7].reduce(shuffle, []);
console.log(JSON.stringify(randomarray));
}
Ronald Fisher et Frank Yates mélangent
Version ES2015 (ES6)
Array.prototype.shuffle2 = function () {
this.forEach(
function (v, i, a) {
let j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
);
return this;
}
Version ES2015 (ES6) optimisée pour Jet
Array.prototype.shuffle3 = function () {
var m = this.length;
while (m) {
let i = Math.floor(Math.random() * m--);
[this[m], this[i]] = [this[i], this[m]];
}
return this;
}
Tableau aléatoire
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;
Je pensais à oneliner pour coller dans la console. Tous les trucs avec .sort
donnaient de faux résultats, voici mon implémentation:
['Bob', 'Amy', 'Joy'].map((person) => `${Math.random().toFixed(10)}${person}`).sort().map((person) => person.substr(12));
Mais ne l'utilisez pas dans le code de production, ce n'est pas optimal et ne fonctionne qu'avec des chaînes.
function shuffleArray(array) {
// Create a new array with the length of the given array in the parameters
const newArray = array.map(() => null);
// Create a new array where each index contain the index value
const arrayReference = array.map((item, index) => index);
// Iterate on the array given in the parameters
array.forEach(randomize);
return newArray;
function randomize(item) {
const randomIndex = getRandomIndex();
// Replace the value in the new array
newArray[arrayReference[randomIndex]] = item;
// Remove in the array reference the index used
arrayReference.splice(randomIndex,1);
}
// Return a number between 0 and current array reference length
function getRandomIndex() {
const min = 0;
const max = arrayReference.length;
return Math.floor(Math.random() * (max - min)) + min;
}
}
console.log(shuffleArray([10,20,30,40,50,60,70,80,90,100]));
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
}
};
Il suffit de passer le tableau pour fonctionner et obtenir en retour le tableau mélangé
// Create a places array which holds the index for each item in the
// passed in array.
//
// Then return a new array by randomly selecting items from the
// passed in array by referencing the places array item. Removing that
// places item each time though.
function shuffle(array) {
let places = array.map((item, index) => index);
return array.map((item, index, array) => {
const random_index = Math.floor(Math.random() * places.length);
const places_value = places[random_index];
places.splice(random_index, 1);
return array[places_value];
})
}
Pour ceux d'entre nous qui ne sont pas très doués mais qui ont accès aux merveilles de lodash, il existe un procédé tel que lodash.shuffle .
Nous sommes toujours en train de brouiller des tableaux en 2019, donc voici mon approche, qui me semble nette et rapide :
const src = [...'abcdefg'];
const shuffle = arr => arr.reduceRight((res,_,__,arr) => [...res,arr.splice(~~(Math.random()*arr.length),1)[0]],[]);
console.log(shuffle(src));
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
Reconstruire tout le tableau, un par un, en plaçant chaque élément à un endroit aléatoire.
[1,2,3].reduce((a,x,i)=>{a.splice(Math.floor(Math.random()*(i+1)),0,x);return a},[])
var ia= [1,2,3];
var it= 1000;
var f = (a,x,i)=>{a.splice(Math.floor(Math.random()*(i+1)),0,x);return a};
var a = new Array(it).fill(ia).map(x=>x.reduce(f,[]));
var r = new Array(ia.length).fill(0).map((x,i)=>a.reduce((i2,x2)=>x2[i]+i2,0)/it)
console.log("These values should be quite equal:",r);
Cette variante de Fisher-Yates est légèrement plus efficace car elle évite de permuter un élément avec lui-même:
function shuffle(array) {
var elementsRemaining = array.length, temp, randomIndex;
while (elementsRemaining > 1) {
randomIndex = Math.floor(Math.random() * elementsRemaining--);
if (randomIndex != elementsRemaining) {
temp = array[elementsRemaining];
array[elementsRemaining] = array[randomIndex];
array[randomIndex] = temp;
}
}
return array;
}
J'ai écrit une fonction de lecture aléatoire par moi-même. La différence ici est qu'il ne répétera jamais une valeur (vérifie le code pour cela): -
function shuffleArray(array) {
var newArray = [];
for (var i = 0; i < array.length; i++) {
newArray.Push(-1);
}
for (var j = 0; j < array.length; j++) {
var id = Math.floor((Math.random() * array.length));
while (newArray[id] !== -1) {
id = Math.floor((Math.random() * array.length));
}
newArray.splice(id, 1, array[j]);
}
return newArray; }
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0].sort((x, z) => {
ren = Math.random();
if (ren == 0.5) return 0;
return ren > 0.5 ? 1 : -1
})
Une solution fonctionnelle utilisant Ramda.
const {map, compose, sortBy, prop} = require('ramda')
const shuffle = compose(
map(prop('v')),
sortBy(prop('i')),
map(v => ({v, i: Math.random()}))
)
shuffle([1,2,3,4,5,6,7])
$=(m)=>console.log(m);
//----add this method to Array class
Array.prototype.shuffle=function(){
return this.sort(()=>.5 - Math.random());
};
$([1,65,87,45,101,33,9].shuffle());
$([1,65,87,45,101,33,9].shuffle());
$([1,65,87,45,101,33,9].shuffle());
$([1,65,87,45,101,33,9].shuffle());
$([1,65,87,45,101,33,9].shuffle());
Mélanger tableau de chaînes:
shuffle = (array) => {
let counter = array.length, temp, index;
while ( counter > 0 ) {
index = Math.floor( Math.random() * counter );
counter--;
temp = array[ counter ];
array[ counter ] = array[ index ];
array[ index ] = temp;
}
return array;
}