This website requires JavaScript.

如何随机&&去重返回新数组

2018.03.30 13:11字数 3326阅读 263喜欢 0评论 0
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.其它解决方法

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作为一个表记录已经被选择过值,若出现重复则直接跳过.

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)

因为一开始看到返回值的时候就想到一个叫做数组扁平化的东西,很悲惨的是只记得名字忘记了实现方案,所以趁此复习一下.这个方案不好的一点就是修改了原数组,这样就无发复用该数组,解决方法是可以在函数中进行一个深拷贝,使用新数组进行操作避免修改原数组.

// 核心是随机排序,对传入的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))