JS: 数组乱序

数组乱序

顾名思义,数组乱序就是把数组存储的值的顺序都打乱。

Fisher–Yates shuffle

著名的洗牌算法,原理就是遍历数组元素,将当前元素与随机抽取的一个剩余元素进行交换。

下列表格遍历元素是从后往前:

随机数范围随机数原始数据结果
1 2 3 4 5 6
[ 0 , 5 ]11 6 3 4 52
[ 0 , 4 ]31 6 3 54 2
[ 0 , 3 ]11 5 36 4 2
[ 0 , 2 ]21 53 6 4 2
[ 0 , 1 ]115 3 6 4 2
[ 0 , 0 ]01 5 3 6 4 2

代码如下:

function shuffle(arr) {
    for (let i=arr.length-1; i>=0; i--) {
        let rIndex = Math.floor(Math.random()*(i+1));
        // 打印交换值
        // console.log(i, rIndex);
        let temp = arr[rIndex];
        arr[rIndex] = arr[i];
        arr[i] = temp;
    }
    return arr;
}

shuffle([1,2,3,4,5,6]); // [1, 5, 3, 6, 4, 2]

现在测试一下是否真的实现了乱序:

// 使用 res 存储结果
let res = {};
let times = 100000;
for (let i=0; i<times; i++) {
    // 使用 [1, 2, 3] 进行简单测试
    let key = JSON.stringify(shuffle([1, 2, 3]));
    res[key] ? res[key]++ : res[key] = 1;
}
for (let key in res) {
    res[key] = Number.parseFloat(res[key]/times *100 ).toFixed(3) + '%';
}
// 从结果可以看出是实现了真正的乱序的
res; 
/*
[1,2,3]: "16.514%"
[1,3,2]: "16.764%"
[2,1,3]: "16.606%"
[2,3,1]: "16.587%"
[3,1,2]: "16.712%"
[3,2,1]: "16.817%"
*/
固定一个值

在乱序的同时,固定一个下标的值,使其位置不变,方法有很多,这里只给出一种:

function shuffle(arr, index) {
    let res = [];
    // 取出固定值
    let fix = arr.splice(index, 1)[0];
    for (let i=arr.length-1; i>=0; i--) {
        let rIndex = Math.floor(Math.random()*(i+1));
        res.push(arr[rIndex]);
        arr.splice(rIndex, 1);
    }
    // 将固定值放入指定位置
    res.splice(index, 0, fix);
    return res;
}
// 多次运行,可以看出数组下标为 1 的值始终是固定的
shuffle([1,2,3,4,5,6], 1);
// [5, 2, 6, 3, 1, 4]
// [5, 2, 6, 3, 4, 1]
// [3, 2, 4, 6, 1, 5]

这里同样测试一下是否实现了真正的乱序:

let res = {};
let times = 100000;
for (let i=0; i<times; i++) {
    // 使用 [1, 2, 3] 进行简单测试,固定数组下标 1 的值
    let key = JSON.stringify(shuffle([1, 2, 3], 1));
    res[key] ? res[key]++ : res[key] = 1;
}
for (let key in res) {
    res[key] = Number.parseFloat(res[key]/times *100 ).toFixed(3) + '%';
}
// 固定的同时,依然是乱序的
res;
/*
[1,2,3]: "49.976%"
[3,2,1]: "50.024%"
*/
注意

需要注意的是,因为数组是引用类型,所以上面的方法都会改变原数组,要想不改变原数组只需稍稍改动一下代码即可,这个很简单,就不写了。

转载于:https://www.cnblogs.com/guolao/p/10173537.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值