JavaScript 数组乱序

所谓数组乱序,其实就是给定一个数组,然后通过处理后返回一个各项顺序打乱的新数组。也就是说处理的时候需要给数组中的每一项分配随机的下标,首先来看一个例子:

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

console.log('before');
console.log(arr);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

for (var i = 0, len = arr.length; i < len; i++) {
var rand = parseInt(Math.random() * len);
var temp = arr[rand];
arr[rand] = arr[i];
arr[i] = temp;
}

console.log('after');
console.log(arr);
// [8, 1, 9, 6, 2, 3, 5, 4, 7]

这里的处理方法其实很简单,就是遍历数组,然后随机取数组中的任意项与当前项交换位置,从而实现打乱数组的顺序。

但这里也有一个问题,就是随机取的任意项可能会跟上一次取的重复,也可能随机生成的索引正好和当前的索引相同(比如例子中 rand === i 的情况)。

下面我们来优化一下代码,增加去重功能。

var arr = ['tom', 'cat', 'dog', 'apple', {name: '张三'}, 'banana', 'orange'];
console.log('before');
console.log(arr);

var randomIndexArr = [];
function generateRandomIndex (len, index) {
var randomIndex = parseInt(Math.random() * len);

if (randomIndexArr.length >= len) {
return null;
}

// 检测生成的索引是否已存在,如果存在则重新生成
if (randomIndex !== index && randomIndexArr.indexOf(randomIndex) === -1) {
randomIndexArr.push(randomIndex);
return randomIndex;
} else {
return generateRandomIndex(len);
}
}

arr.forEach(function (val, i) {
// console.log(val + ' -- ' + i);
var randomIndex = generateRandomIndex(arr.length, i);
// console.log(randomIndexArr);
// console.log(randomIndex);
var temp = arr[randomIndex];
arr[randomIndex] = arr[i];
arr[i] = temp;
});
console.log('after');
console.log(arr);

OK,优化后就比较完善了,其实这就是洗牌算法的一种实现,关于洗牌算法的详细介绍可以参考Fisher–Yates shuffle