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
How to get n no elements randomly from an array
提问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
回答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 .sample
from 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:
笔记:
setsize
is 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
Set
implemented, the set can be replaced with anArray
and.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:
针对已接受答案的表现:
- https://jsperf.com/pick-random-elements-from-an-array
- The performance difference is the greatest on Safari.
- https://jsperf.com/pick-random-elements-from-an-array
- Safari 上的性能差异最大。
回答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);
}
回答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);