이번에는 js 배열의 가중치 확률 정렬 구현 방법을 보여 드리겠습니다. js 배열의 가중치 확률 정렬 구현 시 주의사항은 무엇인가요?
오늘은 페이지 캐러셀을 제어하는 js 함수를 작성했습니다. 큐만 사용하면 매우 간단하지만 각 페이지에 가중치를 할당하는 것이 엄청나게 복잡해지는 것을 고려하면 스위치와 if를 사용하세요. 그렇지 않으면 이를 해결할 수 없어서 js 배열을 사용하여 구현하려고 생각했습니다. 각 캐러셀 페이지를 객체로 추상화한 다음 각 객체는 수동으로 가중치 값을 지정한 다음 함수를 사용하여 배열을 형성해야 합니다. 아래에 요약하면 각 객체를 기준으로 객체를 반환할 확률이 결정되며 코드는 다음과 같습니다.
/** * js数组实现权重概率分配 * @param Array arr js数组,参数类型[Object,Object,Object……] * @return Array 返回一个随机元素,概率为其percent/所有percent之和,参数类型Object * @author shuiguang */ function weight_rand(arr){ //参数arr元素必须含有percent属性,参考如下所示 /* var arr = [{ name : '1', percent : 1 }, { name : '2', percent : 2 }, { name : '3', percent : 1 }, { name : '4', percent : 2 } ]; */ var total = 0; var i, j, percent; //下标标记数组,按照上面的例子,单倍情况下其组成为[1,2,2,3,4,4] var index = new Array(); for (i = 0; i < arr.length; i++) { //判断元素的权重,为了实现小数权重,先将所有的值放大100倍 percent = 'undefined' != typeof(arr[i].percent) ? parseInt(arr[i].percent*100) : 0; for (j = 0; j < percent; j++) { index.push(i); } total += percent; } //随机数值,其值介于0-5的整数 var rand = Math.floor(Math.random() * total); return arr[index[rand]]; }
위의 방법은 가능하지만, 1:1:1 할당(상대값)과 같은 일반적인 복잡한 할당 상황에서는 15%, 25%, 35% 남음(절대값)을 만족할 수 없습니다. 15%:25%:35%의 잔량 비율을 계산하는 것이 매우 번거롭기 때문에 계속해서 위의 함수를 수정하여 백분율 모드를 추가했습니다. 백분율은 마지막 요소의 백분율이나 각 요소의 비율을 계산하지 않고 마지막 요소를 제공합니다. 코드는 다음과 같습니다:
/** * js数组实现权重概率分配,支持数字比模式(支持2位小数)和百分比模式(不支持小数,最后一个元素多退少补) * @param Array arr js数组,参数类型[Object,Object,Object……] * @return Array 返回一个随机元素,概率为其weight/所有weight之和,参数类型Object * @author shuiguang */ function weight_rand(arr){ //参数arr元素必须含有weight属性,参考如下所示 //var arr=[{name:'1',weight:1.5},{name:'2',weight:2.5},{name:'3',weight:3.5}]; //var arr=[{name:'1',weight:'15%'},{name:'2',weight:'25%'},{name:'3',weight:'35%'}]; //求出最大公约数以计算缩小倍数,perMode为百分比模式 var per; var maxNum = 0; var perMode = false; //自定义Math求最小公约数方法 Math.gcd = function(a,b){ var min = Math.min(a,b); var max = Math.max(a,b); var result = 1; if(a === 0 || b===0){ return max; } for(var i=min; i>=1; i--){ if(min % i === 0 && max % i === 0){ result = i; break; } } return result; }; //使用clone元素对象拷贝仍然会造成浪费,但是使用权重数组对应关系更省内存 var weight_arr = new Array(); for (i = 0; i < arr.length; i++) { if('undefined' != typeof(arr[i].weight)) { if(arr[i].weight.toString().indexOf('%') !== -1) { per = Math.floor(arr[i].weight.toString().replace('%','')); perMode = true; }else{ per = Math.floor(arr[i].weight*100); } }else{ per = 0; } weight_arr[i] = per; maxNum = Math.gcd(maxNum, per); } //数字比模式,3:5:7,其组成[0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2] //百分比模式,元素所占百分比为15%,25%,35% var index = new Array(); var total = 0; var len = 0; if(perMode){ for (i = 0; i < arr.length; i++) { //len表示存储arr下标的数据块长度,已优化至最小整数形式减小索引数组的长度 len = weight_arr[i]; for (j = 0; j < len; j++){ //超过100%跳出,后面的舍弃 if(total >= 100){ break; } index.push(i); total++; } } //使用最后一个元素补齐100% while(total < 100){ index.push(arr.length-1); total++; } }else{ for (i = 0; i < arr.length; i++) { //len表示存储arr下标的数据块长度,已优化至最小整数形式减小索引数组的长度 len = weight_arr[i]/maxNum; for (j = 0; j < len; j++){ index.push(i); } total += len; } } //随机数值,其值为0-11的整数,数据块根据权重分块 var rand = Math.floor(Math.random()*total); //console.log(index); return arr[index[rand]]; } var arr=[{name:'1',weight:1.5},{name:'2',weight:2.5},{name:'3',weight:3.5}]; console.log(weight_rand(arr)); var arr=[{name:'1',weight:'15%'},{name:'2',weight:'25%'},{name:'3',weight:'35%'}]; console.log(weight_rand(arr)); var prize_arr = [ {'id':1, 'prize':'平板电脑', 'weight':1}, {'id':2, 'prize':'数码相机', 'weight':2}, {'id':3, 'prize':'音箱设备', 'weight':10}, {'id':4, 'prize':'4G优盘', 'weight':12}, {'id':5, 'prize':'10Q币', 'weight':22}, {'id':6, 'prize':'下次没准就能中哦', 'weight':50} ]; var times = 100000; var prize; var pingban = 0; var shuma = 0; var yinxiang = 0; var youpan = 0; var qb = 0; var xc = 0; var start = new Date().getTime(); for($i=0; $i<times; $i++){ prize = weight_rand(prize_arr); if(prize.prize == '平板电脑') { pingban++; }else if(prize.prize == '数码相机'){ shuma++; }else if(prize.prize == '音箱设备'){ yinxiang++; }else if(prize.prize == '4G优盘'){ youpan++; }else if(prize.prize == '10Q币'){ qb++; }else if(prize.prize == '下次没准就能中哦'){ xc++; } } var stop = new Date().getTime(); console.log('平板电脑:'+pingban/times+', 数码相机:'+shuma/times+', 音箱设备:'+yinxiang/times+', 4G优盘:'+youpan/times+', 10Q币:'+qb/times+', 下次没准就能中哦:'+xc/times); console.log('耗费时间:'+(stop-start)/1000+'秒');
본 코드는 최대공통분모를 통해 첨자배열에 최적화되었으며, 수치비율 모드를 사용하여 최소 수치비율로 최적화되었습니다. 백분율 모드는 성능 소모로 인해 현재 소수점 이하 2자리를 지원하지 않습니다.
js 버전을 작성하고 100,000번의 루프 테스트를 거친 후 for loop가 foreach보다 시간이 절약되고, 온라인이 아닌 업로드된 foreach가 for보다 빠르다는 것을 알았습니다. 하지만 일반적으로 js의 실행 속도는 php의 약 20배 정도입니다. php의 실행 시간은 약 6초이고, js의 실행 시간은 약 0.346초입니다.
rreeePHP 버전이 정수비 모드만 사용한다면 숫자의 증폭이나 최소 공배수를 찾는 알고리즘을 고려할 필요가 없고 단순 누적만 하면 되므로 실행 시간이 크게 단축될 수 있습니다.
이 기사의 사례를 읽은 후 방법을 마스터했다고 생각합니다. 더 흥미로운 정보를 보려면 PHP 중국어 웹사이트의 다른 관련 기사를 주목하세요!
추천 자료:
위 내용은 js 배열에서 가중치 확률 정렬을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!