我有一个这样的数组:
var arr1 = ["a", "b", "c", "d"];
我如何随机化/打乱它?
我有一个这样的数组:
var arr1 = ["a", "b", "c", "d"];
我如何随机化/打乱它?
当前回答
NEW!
更短,可能更快的Fisher Yates洗牌算法
它使用while---按位到底数(最多10个十进制数字(32位))移除了不必要的封盖和其他东西
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之外的所有浏览器上都更快。
如果您有任何问题,请提问。
EDIT
是的,它更快
性能:http://jsperf.com/fyshuffle
使用排名靠前的函数。
编辑计算过多(不需要--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/
可读版本(使用原始版本。这会更慢,vars是无用的,像closures&“;”,代码本身也更短……也许读一下如何“缩小”Javascript代码,顺便说一句,你不能像上面那样用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
}
}
其他回答
有趣的是,没有非变异递归答案:
var shuffle=arr=>{常量重复=(arr,currentIndex)=>{console.log(“什么?”,JSON.stringify(arr))如果(当前索引==0){返回arr;}const randomIndex=数学地板(Math.random()*当前索引);常量swap=arr[currentIndex];arr[currentIndex]=arr[randomIndex];arr[randomIndex]=掉期;返回重复(arr,当前索引-1);}返回递归(arr.map(x=>x),arr.length-1);};var arr=[1,2,3,4,5,[6];console.log(shuffle(arr));控制台日志(arr);
您可以轻松地使用地图和排序:
让unshuffled=['hello','a','t','q',1,2,3,{cats:true}]让洗牌.map(value=>({value,sort:Math.random()})).sort((a,b)=>a.sort-b.sort).map(({value})=>值)console.log(混洗)
我们将数组中的每个元素放在一个对象中,并给它一个随机排序键我们使用随机键排序我们取消映射以获取原始对象
您可以对多态数组进行排序,排序就像Math.random一样随机,这对于大多数目的来说都足够好。
由于元素是根据每次迭代都不会重新生成的一致键进行排序的,并且每次比较都来自相同的分布,因此Math.random分布中的任何非随机性都会被取消。
速度
时间复杂度为O(N log N),与快速排序相同。空间复杂度为0(N)。这不像Fischer Yates洗牌那样高效,但在我看来,代码明显更短,功能更强大。如果你有一个大数组,你当然应该使用Fischer Yates。如果您有一个包含几百个项目的小数组,您可以这样做。
对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;
};
使用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
使用Fisher Yates shuffle算法和ES6:
// Original array
let array = ['a', 'b', 'c', 'd'];
// Create a copy of the original array to be randomized
let shuffle = [...array];
// Defining function returning random value from i to N
const getRandomValue = (i, N) => Math.floor(Math.random() * (N - i) + i);
// Shuffle a pair of two elements at random position j
shuffle.forEach( (elem, i, arr, j = getRandomValue(i, arr.length)) => [arr[i], arr[j]] = [arr[j], arr[i]] );
console.log(shuffle);
// ['d', 'a', 'b', 'c']