jQuery 如何从数组中随机获取n个元素

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19269545/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 23:34:45  来源:igfitidea点击:

How to get n no elements randomly from an array

javascriptjqueryhtmlarrays

提问by Shyam Dixit

I am working on 'how to access elements randomly from an array in javascript'. I found many links regarding this. Like: Get random item from JavaScript array

我正在研究“如何从 javascript 中的数组随机访问元素”。我找到了很多关于这个的链接。喜欢: 从 JavaScript 数组中获取随机项

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

Question:But in this we can choose only one item from the array.If we want more than one elements then how can we achieve this.So please just from this statement how can we get more than one elements from an array.

问题:但是在这里我们只能从数组中选择一项。如果我们想要多个元素,那么我们如何实现这一点。所以请从这个语句中我们如何从数组中获取多个元素。

采纳答案by Bergi

Try this non-destructive (and fast) function:

试试这个非破坏性(和快速)功能:

function getRandom(arr, n) {
    var result = new Array(n),
        len = arr.length,
        taken = new Array(len);
    if (n > len)
        throw new RangeError("getRandom: more elements taken than available");
    while (n--) {
        var x = Math.floor(Math.random() * len);
        result[n] = arr[x in taken ? taken[x] : x];
        taken[x] = --len in taken ? taken[len] : len;
    }
    return result;
}

回答by Abdennour TOUMI

Just two lines :

只有两行:

// Shuffle array
const shuffled = array.sort(() => 0.5 - Math.random());

// Get sub-array of first n elements after shuffled
let selected = shuffled.slice(0, n);


DEMO:

演示

回答by Olalekan Sogunle

There is a one-liner unique solution here

这里有一个单线独特的解决方案

 array.sort(() => Math.random() - Math.random()).slice(0, n)

回答by pomber

Getting 5 random items without changing the original array:

在不改变原始数组的情况下获得 5 个随机项:

const n = 5;
const sample = items
  .map(x => ({ x, r: Math.random() }))
  .sort((a, b) => a.r - b.r)
  .map(a => a.x)
  .slice(0, n);

(Don't use this for big lists)

(不要将此用于大列表)

回答by Laurynas Mali?auskas

create a funcion which does that:

创建一个执行此操作的函数:

var getMeRandomElements = function(sourceArray, neededElements) {
    var result = [];
    for (var i = 0; i < neededElements; i++) {
        result.push(sourceArray[Math.floor(Math.random()*sourceArray.length)]);
    }
    return result;
}

you should also check if the sourceArray has enough elements to be returned. and if you want unique elements returned, you should remove selected element from the sourceArray.

您还应该检查 sourceArray 是否有足够的元素可以返回。如果您希望返回唯一元素,则应从 sourceArray 中删除所选元素。

回答by u283863

Porting .samplefrom the Python standard library:

.sample从 Python 标准库移植:

function sample(population, k){
    /*
        Chooses k unique random elements from a population sequence or set.

        Returns a new list containing elements from the population while
        leaving the original population unchanged.  The resulting list is
        in selection order so that all sub-slices will also be valid random
        samples.  This allows raffle winners (the sample) to be partitioned
        into grand prize and second place winners (the subslices).

        Members of the population need not be hashable or unique.  If the
        population contains repeats, then each occurrence is a possible
        selection in the sample.

        To choose a sample in a range of integers, use range as an argument.
        This is especially fast and space efficient for sampling from a
        large population:   sample(range(10000000), 60)

        Sampling without replacement entails tracking either potential
        selections (the pool) in a list or previous selections in a set.

        When the number of selections is small compared to the
        population, then tracking selections is efficient, requiring
        only a small set and an occasional reselection.  For
        a larger number of selections, the pool tracking method is
        preferred since the list takes less space than the
        set and it doesn't suffer from frequent reselections.
    */

    if(!Array.isArray(population))
        throw new TypeError("Population must be an array.");
    var n = population.length;
    if(k < 0 || k > n)
        throw new RangeError("Sample larger than population or is negative");

    var result = new Array(k);
    var setsize = 21;   // size of a small set minus size of an empty list

    if(k > 5)
        setsize += Math.pow(4, Math.ceil(Math.log(k * 3, 4)))

    if(n <= setsize){
        // An n-length list is smaller than a k-length set
        var pool = population.slice();
        for(var i = 0; i < k; i++){          // invariant:  non-selected at [0,n-i)
            var j = Math.random() * (n - i) | 0;
            result[i] = pool[j];
            pool[j] = pool[n - i - 1];       // move non-selected item into vacancy
        }
    }else{
        var selected = new Set();
        for(var i = 0; i < k; i++){
            var j = Math.random() * n | 0;
            while(selected.has(j)){
                j = Math.random() * n | 0;
            }
            selected.add(j);
            result[i] = population[j];
        }
    }

    return result;
}

Implementation ported from Lib/random.py.

Lib/random.py移植的实现。

Notes:

笔记:

  • setsizeis set based on characteristics in Python for efficiency. Although it has not been adjusted for JavaScript, the algorithm will still function as expected.
  • Some other answers described in this page are not safe according to the ECMAScript specification due to the misuse of Array.prototype.sort. This algorithm however is guaranteed to terminate in finite time.
  • For older browsers that do not have Setimplemented, the set can be replaced with an Arrayand .has(j)replaced with .indexOf(j) > -1.
  • setsize基于 Python 中的特性进行设置以提高效率。尽管没有针对 JavaScript 进行调整,但算法仍会按预期运行。
  • 根据 ECMAScript 规范,由于Array.prototype.sort. 然而,该算法保证在有限时间内终止。
  • 对于尚未Set实现的旧浏览器,可以将集合替换为Array.has(j)替换为.indexOf(j) > -1

Performance against the accepted answer:

针对已接受答案的表现:

回答by Yair Levy

ES6 syntax

ES6 语法

const pickRandom = (arr,count) => {
  let _arr = [...arr];
  return[...Array(count)].map( ()=> _arr.splice(Math.floor(Math.random() * _arr.length), 1)[0] ); 
}

回答by Rory McCrossan

If you want to randomly get items from the array in a loop without repetitions you need to remove the selected item from the array with splice:

如果要在循环中从数组中随机获取项目而不重复,则需要使用splice以下命令从数组中删除所选项目:

var items = [1, 2, 3, 4, 5];
var newItems = [];

for(var i = 0; i < 3; i++) {
    var idx = Math.floor(Math.random() * items.length);
    newItems.push(items[idx]);
    items.splice(idx, 1);
}

Example fiddle

示例小提琴

回答by u2041954

Array.prototype.getnkill = function() {
    var a = Math.floor(Math.random()*this.length);
    var dead = this[a];
    this.splice(a,1);
    return dead;
}

//.getnkill() removes element in the array 
//so if you like you can keep a copy of the array first:

//var original= items.slice(0); 


var item = items.getnkill();

var anotheritem = items.getnkill();

回答by Daniel Birowsky Popeski

Here's a nicely typed version. It doesn't fail. Returns a shuffled array if sample size is larger than original array's length.

这是一个很好的打字版本。它不会失败。如果样本大小大于原始数组的长度,则返回一个混洗过的数组。

function sampleArr<T>(arr: T[], size: number): T[] {
  const setOfIndexes = new Set<number>();
  while (setOfIndexes.size < size && setOfIndexes.size < arr.length) {
    setOfIndexes.add(randomIntFromInterval(0, arr.length - 1));
  }
  return Array.from(setOfIndexes.values()).map(i => arr[i]);
}

const randomIntFromInterval = (min: number, max: number): number =>
  Math.floor(Math.random() * (max - min + 1) + min);