1.问题起因
W姐毫无征兆的在我们的水群里发来一段代码:
var arr = [{q:"1+1=?",a:"2",b:"3",c:"1"},{q:"1+2=?",a:"2",b:"3",c:"7"},{q:"1+0=?",a:"8",b:"3",c:"1"},{q:"1+7=?",a:"8",b:"3",c:"7"},{q:"2+2=?",a:"4",b:"7",c:"1"},{q:"1+3=?",a:"2",b:"4",c:"6"},{q:"1+70=?",a:"72",b:"73",c:"71"},{q:"1+18=?",a:"22",b:"19",c:"21"},{q:"7+11=?",a:"18",b:"23",c:"21"}];
var resArr = [];
for(var i = 0; i<5; i++){
var index = parseInt(Math.random()*10);
resArr.push(arr[index]);
for( var j = 0; j<resArr.length; j++){
if(resArr[j] == resArr[j+1]){
resArr.shift();
--i;
}
}
}
console.log(resArr);
她的目的是想从arr中随机抽取5个不重复的值组成一个新数组resArr.问我代码是否有问题,很遗憾因为我刚睡醒,随便贴了一下代码,运行了一下就说没问题...很快我就被打脸了(也是,如果没问题的话她问个毛..).
大家可以先找一下问题,下面先更正这段代码,然后再给出群里剩下两位大哥的解决方法.
2.代码更正
首先先贴出更正后的代码:
for(var i = 0; i<5; i++){
var index = parseInt(Math.random()*arr.length);//限制范围
resArr.push(arr[index]);
//每次只需要最后一个压入数组的元素resArr[i]与之前所有元素进行比较
//若遇到重复的,将resArr[i]弹出并终止循环即可
for( var j = 0; j<resArr.length-1; j++){
if(resArr[i]== resArr[j]){
resArr.pop();
--i;
break
}
}
}
console.log(resArr);
错的原因就是注释里的,我居然一眼没看出来,真是深感惭愧...看来不能眼高手低,得多敲代码了.
3.其它解决方法
我们4人水群里me和另外两位也给出了不同的思路.
3.1水货me给出的思路
作为小水货的我,当时没有立刻看出来错误的地方,所以直接又写了一个水水的方法,请大家不要见笑....
function solve(arr,num){
var resArr=[],indexArr=[];
for (var j = 0; j < arr.length; j++) {
indexArr[j] = 0;
}
for(var i=0;i<num;){
var index = parseInt(Math.random() * arr.length);
if (!indexArr[index]&& arr[index]) {
indexArr[index] = 1
resArr.push(arr[index]);
i++;
}
}
return resArr;
}
console.log(solve(arr,5))
这里主要使用一个数组indexArr作为一个表记录已经被选择过值,若出现重复则直接跳过.
3.2YC大神给出的解决方法
YC大神作为我们中薪水最高,加班时间最长的,百忙中抽出时间给出了自己的解决方案,在此替W姐感谢过劳肥的YC大神.
function filter(arr, num) {
var newArr = [];
//随机删并返回一个值,因为原数组进行了删除操作,就避免了查重
var pick = function () {
var index = Math.ceil((arr.length * Math.random())) - 1;
return arr.splice(index, 1);
}
for (var i = 0; i < num; i++) {
// newArr.push(pick()[0])//这样写就不用数组扁平化了
newArr.push(pick());
}
return newArr
}
//数组扁平化
function flatten(arr) {
return arr.reduce(function (prev, item) {
return prev.concat(Array.isArray(item) ? flatten(item) : item);
}, []);
}
var b=flatten(filter(arr, 5))
console.log(b)
因为一开始看到返回值的时候就想到一个叫做数组扁平化的东西,很悲惨的是只记得名字忘记了实现方案,所以趁此复习一下.这个方案不好的一点就是修改了原数组,这样就无发复用该数组,解决方法是可以在函数中进行一个深拷贝,使用新数组进行操作避免修改原数组.
3.3joker大哥的解决方案
joker大哥作为我们中身材和脸最好的,以骄傲的姿态给出了我们几个公认最优的解决方案.
//核心是随机排序,对传入的o进行o.length次的随机交换,并使用slice进行截取返回
var shuffle = function (o, num) {
for (var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x) ;
return o.slice(0, 5);
};
console.log(shuffle(arr))
slice()方法返回原数组的一个浅复制,不修改原数组内容.而且效率也高,只用到了一个for循环,如果说有缺点的话就是可读性略差一些,下面展开一下:
var newShuffle=function(o,num){
var j,tmp,i=o.length;
while(i){
j=parseInt(Math.random() * i);
tmp=o[--i];
o[i]=o[j];
o[j]=tmp;
}
return o.slice(0,num)
}
console.log(newShuffle(arr,5))
4如果大家发现和我内容差别不大的博客内容
那个就是w姐的博客..欺负我打字慢..