700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > js打乱数组的顺序_如何用 js 实现一个类似微信红包的随机算法

js打乱数组的顺序_如何用 js 实现一个类似微信红包的随机算法

时间:2018-08-20 16:10:28

相关推荐

js打乱数组的顺序_如何用 js 实现一个类似微信红包的随机算法

如何用 js 实现一个类似微信红包的随机算法

js, 微信红包, 随机算法

"use strict";

/**

*

* @author xgqfrms

* @license MIT

* @copyright xgqfrms

* @created -09-16

* @modified

*

* @description 如何用 js 实现一个类似微信红包的随机算法, 最简单的方法实现微信红包的随机算法

* @difficulty Hard

* @complexity O(n)

* @augments

* @example

* @link /xgqfrms/p/13689802.html

* @link /xgqfrms/tag/%E7%BA%A2%E5%8C%85/

* @link /question/22625187/answer/1478941580

* @solutions

*

*/

const log = console.log;

const shuffle = (arr = []) => {

let len = arr.length;

while (len > 1){

const index = Math.floor(Math.random() * len--);

[

arr[len],

arr[index],

] = [

arr[index],

arr[len],

];

}

return arr;

}

/**

算法需要满足条件:

1. 每个人都可以分到至少 0.01 元;

2. 所有人的分到的红包之和与发出的金额相等,不多不少,刚好分完;

3. 每个人分到金额的概率相等;

*/

/**

假设,发出一个 100元红包,给 10个人分!

算法实现:

1. 按照人数,生成一个等长的数组,且每一个元素的初始化值为 0.01;✅

2. 将剩余的金额(100 - 10 * 0.01), 按照微信设计的规则(假如是正态分布)进行分配出 10 份; ❓

3. 将分配好的红包,依次加入到生成的数组中;✅

4. 最后使用 shuffle 算法打乱数组,并返回; ✅

5. 将计算好的数组,按照抢红包的顺序作为索引值依次取出红包即可.✅

*/

// 精度损失解决方案, 扩大后,再还原 ✅?

const autoRandomRedPackage = (money, num, limit = 0.01) => {

if((money / num) < limit) {

// alert

log(`? 请重新输入红包数量! 减少红包数量,或增加红包金额!`);

log(`❌ 你输入的红包数量太多了,每个人至少要能分到 0.01 元!`);

return false;

} else {

const originMoney = money;

const originLimit = limit;

let multi = 100 * (100 / money);

money *= multi;

limit *= multi;

// log(`multi =`, multi);

const result = [...new Uint8Array(num)].fill(limit, 0, num);

// 1. 将剩余的红包,均分✅,如果有余数,随机的添加到数组的一个元素上

const restLimit = (money - limit * num) / limit;

const reminderLimit = (restLimit % num);

const reminderMoney = reminderLimit * limit;

const averageLimit = (restLimit - reminderLimit) / num;

for (let i = 0; i < num; i++) {

const index = parseInt(Math.random() * averageLimit);

const randomMoney = index * limit;

const leftMoney = (averageLimit - index) * limit;

// 2. 在平均后的范围内,计算出一个随机数,将分配好的红包,依次加入到生成的数组中;✅

result[i] += randomMoney;

// 3. 分配后剩余的红包,随机加入到生成的数组中;✅

const j = parseInt(Math.random() * num);

result[j] += leftMoney;

}

// 4. 将平均后的余数红包,随机加入到生成的数组中;✅

if(reminderMoney > 0) {

const index = parseInt(Math.random() * num);

result[index] += reminderMoney;

}

const temp = shuffle(result).map(i => i / multi);

// log(`temp =`, temp);

const total = temp.reduce((acc, i) => acc += i*multi, 0) / multi;

// log(`total !== originMoney`, total !== originMoney, total, originMoney);

if(total !== originMoney) {

return autoRandomRedPackage(originMoney, num, originLimit);

}

const [min, ...rest1] = temp.sort((a, b) => a - b > 0 ? 1 : -1);

const [max, ...rest2] = temp.sort((a, b) => a - b > 0 ? -1 : 1);

return {

total: total,

result: temp,

desc: `

?️‍♂️ 你输入的红包总额是 ${originMoney} 元, 红包数量是 ${num} 个!

? 最大的红包是 ${max} 元!

? 最小的红包是 ${min} 元!

`,

// desc: `

// ?️‍♂️ 你输入的红包总额是 ${originMoney} 元, 红包数量是 ${num} 个!\n

// ? 最大的红包是 ${max} 元!\n

// ? 最小的红包是 ${min} 元!\n

// `,

};

// return temp;

}

}

const total = arr => arr.result.reduce((acc, i) => acc += i*100, 0) / 100;

// 测试

const test = autoRandomRedPackage(0.1, 11);// ❌ 异常处理

const test0 = autoRandomRedPackage(0.1, 5);

const test1 = autoRandomRedPackage(0.1, 10); // ✅ ok

const test2 = autoRandomRedPackage(1, 10);

const test3 = autoRandomRedPackage(10, 10);

const test4 = autoRandomRedPackage(100, 10);

const test5 = autoRandomRedPackage(100, 11);

log(`\ntest =`, test);

log(`total =`, test && total(test));

log(`\ntest =`, test0);

log(`total =`, test0 && total(test0));

log(`\ntest =`, test1);

log(`total =`, test1 && total(test1));

log(`\ntest =`, test2);

log(`total =`, test2 && total(test2));

log(`\ntest =`, test3);

log(`total =`, test3 && total(test3));

log(`\ntest =`, test4);

log(`total =`, test4 && total(test4));

log(`\ntest =`, test5);

log(`total =`, test5 && total(test5));

/*

$ node node perfect-solution.js

? 请重新输入红包数量! 减少红包数量,或增加红包金额!

❌ 你输入的红包数量太多了,每个人至少要能分到 0.01 元!

test = false

total = false

test = {

total: 0.1,

result: [ 0.03, 0.03, 0.02, 0.01, 0.01 ],

desc: '\n' +

' ?️‍♂️ 你输入的红包总额是 0.1 元, 红包数量是 5 个!\n' +

' ? 最大的红包是 0.03 元!\n' +

' ? 最小的红包是 0.01 元!\n' +

''

}

total = 0.1

test = {

total: 0.1,

result: [

0.01, 0.01, 0.01,

0.01, 0.01, 0.01,

0.01, 0.01, 0.01,

0.01

],

desc: '\n' +

' ?️‍♂️ 你输入的红包总额是 0.1 元, 红包数量是 10 个!\n' +

' ? 最大的红包是 0.01 元!\n' +

' ? 最小的红包是 0.01 元!\n' +

''

}

total = 0.1

test = {

total: 1,

result: [

0.16, 0.13, 0.13,

0.12, 0.09, 0.08,

0.08, 0.08, 0.07,

0.06

],

desc: '\n' +

' ?️‍♂️ 你输入的红包总额是 1 元, 红包数量是 10 个!\n' +

' ? 最大的红包是 0.16 元!\n' +

' ? 最小的红包是 0.06 元!\n' +

''

}

total = 1

test = {

total: 10,

result: [

2.43, 1.73, 1.43,

1.36, 1, 0.78,

0.66, 0.28, 0.25,

0.08

],

desc: '\n' +

' ?️‍♂️ 你输入的红包总额是 10 元, 红包数量是 10 个!\n' +

' ? 最大的红包是 2.43 元!\n' +

' ? 最小的红包是 0.08 元!\n' +

''

}

total = 10

test = {

total: 100,

result: [

23.71, 16.9, 13.24,

12, 10, 8.6,

8.33, 3.6, 1.92,

1.7

],

desc: '\n' +

' ?️‍♂️ 你输入的红包总额是 100 元, 红包数量是 10 个!\n' +

' ? 最大的红包是 23.71 元!\n' +

' ? 最小的红包是 1.7 元!\n' +

''

}

total = 100

test = {

total: 100,

result: [

17.59, 11.68, 11.55,

10.2, 8.83, 8.81,

8.24, 7.55, 7.44,

6.66, 1.45

],

desc: '\n' +

' ?️‍♂️ 你输入的红包总额是 100 元, 红包数量是 11 个!\n' +

' ? 最大的红包是 17.59 元!\n' +

' ? 最小的红包是 1.45 元!\n' +

''

}

total = 100

*/

refs

/xgqfrms/tag/红包/

©xgqfrms -

发布文章使用:只允许注册用户才可以访问!

xgqfrms

标签:微信,随机算法,红包,js,微信红包

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。