如何从数组中获取随机元素的数量?

196

我正在研究如何在JavaScript中随机访问数组元素。我发现了许多相关链接,比如: 从JavaScript数组获取随机项

var item = items[Math.floor(Math.random()*items.length)];

但是在这种情况下,我们只能从数组中选择一个项目。如果我们想要多个元素,该怎么办?如何从数组中获取多个元素?


7
只需要多次执行它吗? - Bergi
4
从这个声明中我们可以做到这一点吗?循环生成了重复项。 - Shyam Dixit
1
从那个确切的语句中,你无法获得多个元素。 - Sébastien
2
啊,你本应该说出你不想要重复的数字。那就看看 Unique random numbers in O(1)? 和我的回答:Generate unique number within range (0 - X), keeping a history to prevent duplicates - Bergi
打乱数组并获取前N个,见https://dev59.com/IXE95IYBdhLWcg3wHqMV。 - georg
1
我创建了一个 JsPerf 来测试这里的一些解决方案。@Bergi 的解决方案似乎是最好的,而我的解决方案在需要从数组中获取多个元素时效果更好。http://jsperf.com/k-random-elements-from-array - Tibos
26个回答

0

它从srcArray中逐个提取随机元素,直到获取足够的元素或者srcArray中没有更多元素可供提取。 快速而可靠。

function getNRandomValuesFromArray(srcArr, n) {
    // making copy to do not affect original srcArray
    srcArr = srcArr.slice();
    resultArr = [];
    // while srcArray isn't empty AND we didn't enough random elements
    while (srcArr.length && resultArr.length < n) {
        // remove one element from random position and add this element to the result array
        resultArr = resultArr.concat( // merge arrays
            srcArr.splice( // extract one random element
                Math.floor(Math.random() * srcArr.length),
                1
            )
        );
    }

    return resultArr;
}


欢迎来到SO!在发表答案时,重要的是要说明代码如何工作和/或如何解决OP的问题 :) - Joel

0

实际上你不需要排序,你只需要生成一个随机的子数组长度:

const myArray = ["January", "February", "March", "April", "May", "June", "July"];

const randomNumGenerator = () => Math.floor(Math.random() * myArray.length)

const result = [
  ...new Set(
    Array.from({
        length: randomNumGenerator() + 1
      },
      _ => myArray[randomNumGenerator()])
  )
]

console.log(result)


0
这是我使用的一个函数,它允许您轻松地对数组进行有或无替换的抽样:
  // Returns a random sample (either with or without replacement) from an array
  const randomSample = (arr, k, withReplacement = false) => {
    let sample;
    if (withReplacement === true) {  // sample with replacement
      sample = Array.from({length: k}, () => arr[Math.floor(Math.random() *  arr.length)]);
    } else { // sample without replacement
      if (k > arr.length) {
        throw new RangeError('Sample size must be less than or equal to array length         when sampling without replacement.')
      }
      sample = arr.map(a => [a, Math.random()]).sort((a, b) => {
        return a[1] < b[1] ? -1 : 1;}).slice(0, k).map(a => a[0]); 
      };
    return sample;
  };

使用它很简单:

无替换(默认行为)

randomSample([1, 2, 3], 2) 可能返回 [2, 1]

有替换

randomSample([1, 2, 3, 4, 5, 6], 4) 可能返回 [2, 3, 3, 2]


0
var getRandomElements = function(sourceArray, requiredLength) {
    var result = [];
    while(result.length<requiredLength){
        random = Math.floor(Math.random()*sourceArray.length);
        if(result.indexOf(sourceArray[random])==-1){
            result.push(sourceArray[random]);
        }
    }
    return result;
}

-2

items.sort(() => (Math.random() > 0.5 ? 1 : -1)).slice(0, count);

将数组 items 随机排序并截取前 count 个元素。


结果略微不均匀分布。 - Patrolin

-2

这里是最正确的答案,它将为您提供随机+独特的元素。

function randomize(array, n)
{
    var final = [];
    array = array.filter(function(elem, index, self) {
        return index == self.indexOf(elem);
    }).sort(function() { return 0.5 - Math.random() });

    var len = array.length,
    n = n > len ? len : n;

    for(var i = 0; i < n; i ++)
    {
        final[i] = array[i];
    }

    return final;
}

// randomize([1,2,3,4,5,3,2], 4);
// Result: [1, 2, 3, 5] // Something like this

这个随机化似乎有些奇怪 - 在8个元素的数组大小为148的情况下,我尝试了9次,其中6次结果相同。你可以考虑切换到Fisher-Yates方法;这就是我所做的,现在效果好多了。 - asetniop
这需要二次时间,因为它执行了一个糟糕的唯一性检查,并且由于使用随机比较进行排序,没有平等地选择每个项目的机会。 - Ry-

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接