受到世界杯的影响,我想写一个程序,可以手动录入一场比赛所有盘口的赔率,胜平负3种情况、让球胜平负3种情况、比分26种情况、进球数8种情况、半全场9种情况,有的场次不能单买胜平负、让球胜平负,或者直接不开这种盘口,但相互之间串在一起不受限制。
以A、B、C、D为场次的标识,默认一种情况投入10块钱,算出能够赢的钱再排序。当只有一场比赛的时候,很好算。当有A、B两场时,场次本身的结果有A、B、AB,当有A、B、C、三场的时候,场次本身组合的结果就有A、B、C、AB、AC、BC、ABC。
首先要有得出涉及场次所有组合的算法,其中的规律在于,当处理的场次序号时i,i本身是一种组合,先把i之前的组合和i结合一遍,再把i放进去,依次类推,直到数组的最后一项,那么算法如下。
const teamList = ["A", "B", "C", "D"];
let teamCombinationList = [];
getTeamCombinationList(0);
function getTeamCombinationList(index) {
const list = [];
teamCombinationList.forEach((el) => {
list.push([...el, teamList[index]]);
});
list.push([teamList[index]]);
teamCombinationList = [...teamCombinationList, ...list];
if (index < teamList.length - 1) {
getTeamCombinationList(index + 1);
}
}
结果如下
[
[ 'A' ],
[ 'A', 'B' ],
[ 'B' ],
[ 'A', 'C' ],
[ 'A', 'B', 'C' ],
[ 'B', 'C' ],
[ 'C' ],
[ 'A', 'D' ],
[ 'A', 'B', 'D' ],
[ 'B', 'D' ],
[ 'A', 'C', 'D' ],
[ 'A', 'B', 'C', 'D' ],
[ 'B', 'C', 'D' ],
[ 'C', 'D' ],
[ 'D' ]
]
此时只需遍历teamCombinationList
,有一个就是单场、有两个就是2串1、有三个就是3穿1,因为场次的个数不确定,现在需要一个通用算法实现类似多层for循环的结果。因为每个场次最多有51种结果,以A0、A1这种方式简单替代下。
已
[
["A0", "A1", "A2"],
["B3", "B4"],
],
举例,所有的结果是 'A0B3','A0B4', 'A1B3', 'A1B4', 'A2B3','A2B4'
算法核心逻辑是实现一个for循环,如果不是最后一个场次,则当前结果传给下一个递归,再进行for循环,如果是最后一个场次,则组合结果放进公共数组里。
/**
* A 'A0','A1','A2'
* B 'B3','B4'
* C 'C0','C5'
*/
let oddResultList = [];
let teamCombinationList = [
[["A0", "A1", "A2"]],
[
["A0", "A1", "A2"],
["B3", "B4"],
],
[["B3", "B4"]],
[
["A0", "A1", "A2"],
["C0", "C5"],
],
[
["A0", "A1", "A2"],
["B3", "B4"],
["C0", "C5"],
],
[
["B3", "B4"],
["C0", "C5"],
],
[["C0", "C5"]],
];
for (let i = 0; i < teamCombinationList.length; i++) {
const list = teamCombinationList[i];
againForEach([], 0);
function againForEach(againList, index) {
list[index].forEach((el) => {
if (index === list.length - 1) {
let str = "";
[...againList, el].forEach((item) => {
str += item;
});
oddResultList.push(str);
} else {
againForEach([...againList, el], index + 1);
}
});
}
}
oddResultList
的结果如下
[
'A0', 'A1', 'A2', 'A0B3',
'A0B4', 'A1B3', 'A1B4', 'A2B3',
'A2B4', 'B3', 'B4', 'A0C0',
'A0C5', 'A1C0', 'A1C5', 'A2C0',
'A2C5', 'A0B3C0', 'A0B3C5', 'A0B4C0',
'A0B4C5', 'A1B3C0', 'A1B3C5', 'A1B4C0',
'A1B4C5', 'A2B3C0', 'A2B3C5', 'A2B4C0',
'A2B4C5', 'B3C0', 'B3C5', 'B4C0',
'B4C5', 'C0', 'C5'
]
获得所有结果后进行排序,我一开始是调接口实现,后台基于nodejs实现的,当场次少于等于3场返回还是很快,但场次是4的时候,报错内存溢出,我以为是自己算法写的有问题,造成死循环,但是前面也没啥问题...
因为实际的数据结构比较复杂,我就使用--max-old-space-size命令加大,打开任务管理器,发现内存一致逐渐攀升道6、7千M的位置就不上去,加了几个输出,发现很快就算出结果,因为数组本身存储的是引用,其实这一块是不会内存溢出的,而是卡在了排序上,把排序代码去掉,还是不行,因为要把所有数据序列化后再返给前端,那么这个json是很大的。
其实所有数据都在前端的时候,是没必要再掉接口的,于是我把代码移到前端执行,4个场次虽然慢了些,但还是能展示,5个场次的时候也不行了,页面崩溃。
1个场次的时候最多51种,2个场次最多3015,3个场次最多166359,4个场次最多9150603,5个场次仅仅是计算处所有结果页面就崩溃了。至于优化的方式,尝试用简单的标记代替对象,等用到的时候再解析读取,然而一顿操作后还是不行,5个场次有503284374种结果,上亿级别了,我只是执行Array(503284374).fill(1)
就崩溃了。
网友评论