背景
如何将一个数组中的元素随机打乱?
如何又却能确保一个元素的位置不变,将其他元素位置打乱?
问题:用js实现一个随机打乱数组顺序的函数,要求可以设定数组种任意1个元素的位置不变,其他位置的元素位置随机变化。
基本思路
先理解出基本的洗牌算法,将一个数组全部打乱,再在这个基础上增添条件。
需要设置一个下标的数字不变,基本思路:
- 首先判断下标数字是合法的,即传入的数组中有该下标;
- 在for循环时,当遍历到指定的
index
时,应当跳过此次循环; - 在生成随机数时,应当保证 生成的随机数 !==
index
;
解决
首先我们先不考虑可以设定数组任意一个元素的位置不变这一条件,直接先考虑如何打乱一个数组。
利用Fisher–Yates shuffle
算法
Array.prototype.shuffle = function() {
const arr = this;
for (let i = arr.length -1; i >= 0; i--) {
// 获取随机数
const randomIndex = Math.floor(Math.random() * (i + 1));
// 交换值
[arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]];
}
return arr;
};
然后我们在增加条件,可以设定数组中任意1个元素的位置不变。
function shuffleWithoutIndex(arr, index) {
if (typeof arr === undefined) return;
if (typeof index === undefined) return;
if (index < 0 || index > arr.length -1) {
return;
}
const array = arr;
for (let i = array.length - 1; i >= 0; i--) {
// 跳过需要固定的那个元素
if (i === index) { continue; }
let randomIndex = -1;
// 获取随机数,保证随机数不等于需要固定的index
do {
randomIndex = Math.floor(Math.random() * (i + 1));
} while(randomIndex === index);
// 交换值
[array[i], array[randomIndex]] = [array[randomIndex], array[i]];
}
return array;
}
参考资料
洗牌算法介绍-维基百科
洗牌算法实现
Math.random()-MDN