3

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姐的博客..欺负我打字慢..
图片描述

W姐的博客地址


梦中的贝壳
41 声望6 粉丝