How to randomize (shuffle) a JavaScript array?
我有一个这样的数组:
1 | var arr1 = ["a","b","c","d"]; |
我如何随机化/洗牌?
事实上,无偏随机洗算法是fisher-yates(又称knuth)随机洗。
请参阅https://github.com/coolaj86/knuth-shuffle
你可以在这里看到一个很好的可视化效果(和链接到这个的原始帖子)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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); |
关于所用算法的更多信息。
下面是一个Durstenfeld Shuffle的javascript实现,这是Fisher Yates的计算机优化版本:
1 2 3 4 5 6 7 8 9 10 11 12 | /** * 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; } } |
Fisher-Yates算法的工作原理是为每个原始数组元素选择一个随机元素,然后将其从下一个绘图中排除。就像从一副牌中随机挑选一样。
这种排除是以一种巧妙的方式完成的(由Durstenfeld发明,供计算机使用),方法是将选中的元素与当前元素交换,然后从其余元素中选择下一个随机元素。为了获得最佳的效率,循环向后运行,从而简化随机选取(它可以始终从0开始),并且跳过最后一个元素,因为不再有其他选择。
该算法的运行时间为O(N)。注意,洗牌是在适当的位置进行的。因此,如果不想修改原始数组,请先用
新的ES6允许我们一次分配两个变量。当我们想交换两个变量的值时,这特别方便,因为我们可以在一行代码中进行交换。下面是使用此功能的同一函数的较短形式。
1 2 3 4 5 6 | 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]]; } } |
。
[社区编辑:此答案不正确;请参阅评论。它被留在这里供将来参考,因为这个想法并不罕见。]
1 2 3 | [1,2,3,4,5,6].sort(function() { return .5 - Math.random(); }); |
可以(或应该)将其用作数组中的原型:
来自克里斯托夫:
1 2 3 4 5 6 7 8 9 10 11 | 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; } |
号
使用underline.js库。方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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(); |
使用map和sort可以很容易地做到这一点:
1 2 3 4 5 6 | 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分布中的任何非随机性都会被取消。
新!
更短,可能更快的fisher-yates shuffle算法
1 2 3 | 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字节
演示http://jsfiddle.net/vvpoma8w/
*在除Chrome以外的所有浏览器上都可能更快。
如果你有什么问题,就问吧。
编辑
是的,比较快
性能:http://jspef.com/fyshuffle
使用最高投票功能。
编辑有一个计算超过(不需要——C+1),没有人注意到
更短(4字节)更快(测试!).
1 2 3 | 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 } |
号
在其他地方缓存
http://jsfiddle.net/vvpoma8w/2/
可读版本(使用原始版本。这比较慢,var是无用的,就像闭包一样,代码本身也更短…也许读一下如何"缩小"javascript代码,顺便说一句,你不能在像上面这样的javascript浏览器中压缩以下代码。)
1 2 3 4 5 6 7 8 9 10 11 | 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 } } |
号
小数组的一个非常简单的方法就是:
1 2 3 | const someArray = [1, 2, 3, 4, 5]; someArray.sort(() => Math.random() - 0.5); |
号
它的效率可能不是很高,但对于小型阵列来说,它工作得很好。这里有一个例子,你可以看到它有多随机(或不随机),以及它是否适合你的用例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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)); |
1 2 3 4 | Randomize! <button id="trigger">Generate</button> <p id="results">0 1 2 3 4 5 6 7 8 9 </p> |
。
添加到@laurens holsts答案中。压缩率为50%。
1 2 3 4 5 6 7 8 9 | 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 }; |
。
有些答案可以使用ES6语法缩短。
ES6纯,迭代1 2 3 4 5 6 7 8 | 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 }; |
号
我个人使用这个功能是因为它是纯的,相对简单的,而且根据我对谷歌Chrome的测试,它是最有效的(与其他纯版本相比)。
将阵列移动到位1 2 3 4 5 6 | 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]] } } |
可靠性和性能
正如您在本页中看到的,过去这里提供的解决方案不正确。因此,考虑到可靠性和性能,我编写了以下函数来测试任何纯(无副作用)数组随机化函数。我用它来测试这个答案中的所有选项。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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}`) } |
。typescript-纯数组随机化函数的类型
您可以使用以下任一项。
1 2 3 4 | type GetShuffledArr= <T>(arr:Array<T>) => Array<T> interface IGetShuffledArr{ <T>(arr:Array<T>): Array<T> } |
其他选项
ES6纯,递归
1 2 3 4 5 | 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纯使用array.map
1 2 3 4 5 6 7 | 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纯使用array.reduce
1 2 3 4 5 6 7 8 9 | 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] ) } |
这个版本比迭代纯版本效率稍低。
有了ES2015,您可以使用它:
1 2 3 4 5 6 7 8 | 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 | [1, 2, 3, 4, 5, 6, 7].shuffle(); |
。
1 2 3 4 5 6 7 8 | 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; }; |
。
我在"被作者删除"的答案中找到了这个变体,它是关于这个问题的一个副本。与其他一些已经有很多赞成票的答案不同,这是:
这里有一个JSfiddle显示它在使用中。
1 2 3 4 | 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 | // array var fruits = ["Banana","Orange","Apple","Mango"]; // random fruits.sort(function(a, b){return 0.5 - Math.random()}); // out console.log(fruits); |
号
请在javascript排序数组中引用
递归解决方案:
1 2 3 4 5 | 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)); }; |
首先,在这里查看一下不同排序方法在javascript中的视觉比较。
其次,如果您快速查看上面的链接,您会发现与其他方法相比,
1 2 3 4 5 6 | function shuffle(array) { var random = array.map(Math.random); array.sort(function(a, b) { return random[array.indexOf(a)] - random[array.indexOf(b)]; }); } |
号
编辑:正如@gregers所指出的,比较函数是用值而不是索引来调用的,这就是为什么需要使用
费希尔·耶茨用JavaScript洗牌。我在这里发布这篇文章是因为使用了两个实用函数(swap和randint)与这里的其他答案相比,它澄清了算法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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); } } |
不更改源数组的随机播放函数
更新:这里我建议一个相对简单(不是从复杂性的角度)和短的算法,可以很好地处理小尺寸的数组,但它肯定会比传统的Durstenfeld算法在处理大数组时花费更多。你可以在这个问题的最高级回复中找到德斯坦菲尔德。
原始答案:
如果不希望shuffle函数改变源数组,可以将其复制到一个局部变量,然后用一个简单的shuffling逻辑执行其余的操作。
1 2 3 4 5 6 7 8 9 10 11 | 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; } |
。
洗牌逻辑:选取一个随机索引,然后将相应的元素添加到结果数组中,并从源数组副本中删除它。重复此操作,直到源数组变为空。
如果你真的想要短一点,我可以做到以下几点:
1 2 3 4 5 6 7 8 9 10 | 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; } |
号
所有其他答案都是基于math.random()的,它速度快,但不适用于密码学级别的随机化。
下面的代码使用著名的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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)); |
。
Fisher Yates的另一个实现,使用严格的模式:
1 2 3 4 5 6 7 8 9 10 11 | 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; } |
。
1 2 3 4 5 6 7 | function shuffle(array) { array.sort(() => Math.random() - 0.5); } let arr = [1, 2, 3]; shuffle(arr); alert(arr); |
https://javascript.info/task/shuffle
只是为了在馅饼里插上一根手指。在这里,我介绍了Fisher Yates Shuffle的递归实现(我认为)。它赋予了统一的随机性。
注:对于正实数,
1 2 3 4 | 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]))); |
对COOLAJ86答案的简单修改,不修改原始数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /** * 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; }; |
号
使用ES6功能的现代短内联解决方案:
1 | ['a','b','c','d'].map(x => [Math.random(), x]).sort(([a], [b]) => a - b).map(([_, x]) => x); |
号
(用于教育目的)
虽然已经建议了许多实现,但我认为使用foreach循环可以使它变得更短更容易,因此我们不需要担心计算数组长度,而且可以安全地避免使用临时变量。
1 2 3 4 5 6 7 8 9 | 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) |
号
从理论上讲,我认为最优雅的方法是得到一个介于0和n之间的随机数!-1并计算从
当使用IEEE754双精度浮点数进行计算时,您可以期望随机生成器提供大约15个小数。既然你有15岁!=1307674368000(有13位数字),您可以使用以下函数与最多包含15个元素的数组一起使用,并假设最多包含14个元素的数组没有明显的偏差。如果您处理的是固定大小的问题,需要多次计算此无序处理操作的次数,那么您可能需要尝试以下代码,因为它只使用一次
将不使用以下函数,但我还是给出了它;它根据此消息中使用的一对一映射(枚举排列时最自然的映射)返回
1 2 3 4 5 6 7 8 9 10 11 | 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个元素;它返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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; } |
号
现在,你只想要:
1 2 3 4 5 | 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个元素的数组,您可以安全地认为绝对没有偏差。
有趣的是,没有不可变的递归答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | var shuffle = arr => { const recur = (arr,currentIndex)=>{ console.log("What?",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); |
号
最短的
1 2 3 4 | 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; } |
。
使用array.splice()随机化数组
1 2 3 4 5 6 7 8 9 10 | 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])); |
号
演示
随机化数组
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 2 3 4 5 6 7 8 | 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; } |
号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // 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]; }) } |
号
我看到还没有人给出一个可以连接而不扩展数组原型的解决方案(这是一个糟糕的实践)。使用稍微不太知名的
1 | var randomsquares = [1, 2, 3, 4, 5, 6, 7].reduce(shuffle).map(n => n*n); |
号
您可能希望传递第二个参数
1 2 3 | // 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); |
号
让我们把
1 2 3 4 5 6 7 8 9 10 11 | 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; } |
号
您可以在jsFiddle或此处看到它的作用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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)); } |
号
通过使用随机播放阵列模块,您可以随机播放阵列。这是一个简单的代码。
1 2 3 4 5 6 | var shuffle = require('shuffle-array'), //collection = [1,2,3,4,5]; collection = ["a","b","c","d","e"]; shuffle(collection); console.log(collection); |
号
希望这有帮助。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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 } }; |
。
只需将数组传递给函数,然后返回洗牌数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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])); |
号
我正在考虑在控制台上粘贴一行程序。所有与
1 | ['Bob', 'Amy', 'Joy'].map((person) => `${Math.random().toFixed(10)}${person}`).sort().map((person) => person.substr(12)); |
号
但不要在生产代码中使用它,它不是最佳的,只适用于字符串。
罗纳德·费舍尔和弗兰克·耶茨洗牌
ES2015 (ES6) release
号
1 2 3 4 5 6 7 8 9 | 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; } |
Jet optimized ES2015 (ES6) release
号
1 2 3 4 5 6 7 8 | 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; } |
。
考虑到将其应用于in-loco或新的不可变数组,下面是其他解决方案,下面是建议的实现:
1 2 3 4 5 6 7 8 9 10 11 12 | 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; }; |
。
我自己写了一个随机播放函数。这里的区别在于它永远不会重复一个值(为此检查代码):。-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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; } |
号
d3.js提供了fisher-yates shuffle的内置版本:
1 | console.log(d3.shuffle(["a","b","c","d"])); |
1 | <script src="http://d3js.org/d3.v5.min.js"> |
d3.shuffle(array[, lo[, hi]]) <>
Randomizes the order of the specified array using the Fisher–Yates shuffle.
对于我们这些不是很有天赋但能接触到罗达什奇观的人来说,有一件事就是罗达什洗牌。
随机推送或取消推送(在开头添加)。
1 2 3 4 | ['a', 'b', 'c', 'd'].reduce((acc, el) => { Math.random() > 0.5 ? acc.push(el) : acc.unshift(el); return acc; }, []); |
重建整个数组,逐个将每个元素放在随机位置。
1 | [1,2,3].reduce((a,x,i)=>{a.splice(Math.floor(Math.random()*(i+1)),0,x);return a},[]) |
1 2 3 4 5 6 7 | 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); |
Fisher Yates的这种变化稍微更为有效,因为它避免了将一个元素与自身交换:
1 2 3 4 5 6 7 8 9 10 11 12 | 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; } |
。
1 2 3 4 5 | [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 }) |
1 2 3 4 5 6 7 8 9 10 11 12 | $=(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()); |
使用Ramda的功能解决方案。
1 2 3 4 5 6 7 8 9 | 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]) |
Shuffle array of strings:
1 2 3 4 5 6 7 8 9 10 11 | 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; } |