배열에서 여러 개의 임의 요소를 가져오는 방법은 무엇입니까?
저는 'javascript의 배열에서 임의로 요소에 접근하는 방법'을 연구하고 있습니다.저는 이것과 관련된 많은 링크를 찾았습니다.좋아요: JavaScript 배열에서 임의 항목 가져오기
var item = items[Math.floor(Math.random()*items.length)];
그러나 이 경우 배열에서 하나의 항목만 선택할 수 있습니다.두 개 이상의 요소를 원하는 경우 어떻게 이를 달성할 수 있습니까?어레이에서 두 개 이상의 요소를 가져오려면 어떻게 해야 합니까?
단 두 줄:
// 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);
데모:
이 비파괴적(그리고 빠른) 기능을 사용해 보십시오.
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;
}
여기에는 한 줄로 된 고유한 솔루션이 있습니다.
array.sort(() => Math.random() - Math.random()).slice(0, n)
컬렉션에서 컬렉션 크기까지의 고유 키에서 하나 또는 n개의 임의 요소를 가져옵니다.
_.sample([1, 2, 3, 4]);
// => 2
_.sampleSize([1, 2, 3], 2);
// => [3, 1]
_.sampleSize([1, 2, 3], 3);
// => [2, 3, 1]
원래 배열을 변경하지 않고 랜덤 항목 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);
(큰 목록에는 사용 안 함)
팅.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) / Math.log(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;
}
Lib/random.py 에서 포팅된 구현입니다.
주의:
setsize
효율성을 위해 Python의 특성을 기반으로 설정됩니다.자바스크립트에 맞게 조정되지는 않았지만, 알고리즘은 여전히 예상대로 작동할 것입니다.- 중 는 ECMA 하지 않습니다. 이 답변은 ECMA 스크립트가 잘못 사용되었기 입니다.
Array.prototype.sort
그러나 이 알고리즘은 제한된 시간 내에 종료됩니다. - 를사하지않는경이우브라의가 없는
Set
을 구, 세는다대로수있체습다니로 바꿀 수 .Array
그리고..has(j)
로대된으로.indexOf(j) > -1
.
승인된 답변에 대한 성능:
- https://jsperf.com/pick-random-elements-from-an-array
- 사파리에서는 성능 차이가 가장 큽니다.
다음을 수행하는 함수를 만듭니다.
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;
}
또한 sourceArray에 반환할 요소가 충분한지 확인해야 합니다.고유한 요소를 반환하려면 sourceArray에서 선택한 요소를 제거해야 합니다.
배열에서 을 반복 가져오려면 을 제거하면 .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);
}
console.log(newItems);
ES6 구문
const pickRandom = (arr,count) => {
let _arr = [...arr];
return[...Array(count)].map( ()=> _arr.splice(Math.floor(Math.random() * _arr.length), 1)[0] );
}
아무도 이 방법을 언급하지 않았다니 믿을 수 없습니다. 꽤 깨끗하고 직설적입니다.
const getRnd = (a, n) => new Array(n).fill(null).map(() => a[Math.floor(Math.random() * a.length)]);
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();
여기 멋지게 타이핑된 버전이 있습니다.실패하지 않습니다.샘플 크기가 원래 배열의 길이보다 큰 경우 혼합 배열을 반환합니다.
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);
이 답변에서, 저는 모든 요소가 무작위 하위 배열을 가질 수 있는 동등한 기회를 주는 최고의 방법을 알아야 한다는 테스트를 여러분과 공유하고자 합니다.
방법 01
array.sort(() => Math.random() - Math.random()).slice(0, n)
이 방법을 사용하면 일부 요소는 다른 요소와 비교하여 더 높은 확률을 가집니다.
calculateProbability = function(number=0 ,iterations=10000,arraySize=100) {
let occ = 0
for (let index = 0; index < iterations; index++) {
const myArray= Array.from(Array(arraySize).keys()) //=> [0, 1, 2, 3, 4, ... arraySize]
/** Wrong Method */
const arr = myArray.sort(function() {
return val= .5 - Math.random();
});
if(arr[0]===number) {
occ ++
}
}
console.log("Probability of ",number, " = ",occ*100 /iterations,"%")
}
calculateProbability(0)
calculateProbability(0)
calculateProbability(0)
calculateProbability(50)
calculateProbability(50)
calculateProbability(50)
calculateProbability(25)
calculateProbability(25)
calculateProbability(25)
방법 2
이 방법을 사용하면 요소의 확률이 동일합니다.
const arr = myArray
.map((a) => ({sort: Math.random(), value: a}))
.sort((a, b) => a.sort - b.sort)
.map((a) => a.value)
calculateProbability = function(number=0 ,iterations=10000,arraySize=100) {
let occ = 0
for (let index = 0; index < iterations; index++) {
const myArray= Array.from(Array(arraySize).keys()) //=> [0, 1, 2, 3, 4, ... arraySize]
/** Correct Method */
const arr = myArray
.map((a) => ({sort: Math.random(), value: a}))
.sort((a, b) => a.sort - b.sort)
.map((a) => a.value)
if(arr[0]===number) {
occ ++
}
}
console.log("Probability of ",number, " = ",occ*100 /iterations,"%")
}
calculateProbability(0)
calculateProbability(0)
calculateProbability(0)
calculateProbability(50)
calculateProbability(50)
calculateProbability(50)
calculateProbability(25)
calculateProbability(25)
calculateProbability(25)
정답은 https://stackoverflow.com/a/46545530/3811640 링크에 게시되어 있습니다.
2020
불변의 맥락에서 작동하는 비파괴적 기능 프로그래밍 스타일입니다.
const _randomslice = (ar, size) => {
let new_ar = [...ar];
new_ar.splice(Math.floor(Math.random()*ar.length),1);
return ar.length <= (size+1) ? new_ar : _randomslice(new_ar, size);
}
console.log(_randomslice([1,2,3,4,5],2));
편집: 몇 가지 요소만 가져오려면 이 솔루션이 여기에 제시된 다른 솔루션보다 느립니다(소스 어레이를 두 배로 구성).이 솔루션의 속도는 원래 어레이에 있는 요소의 수에만 따라 결정되는 반면, 스플라이싱 솔루션의 속도는 출력 어레이에 필요한 요소의 수에 따라 결정됩니다.
반복되지 않는 임의 요소를 원하는 경우 배열을 섞고 원하는 만큼만 얻을 수 있습니다.
function shuffle(array) {
var counter = array.length, temp, index;
// While there are elements in the array
while (counter--) {
// Pick a random index
index = (Math.random() * counter) | 0;
// And swap the last element with it
temp = array[counter];
array[counter] = array[index];
array[index] = temp;
}
return array;
}
var arr = [0,1,2,3,4,5,7,8,9];
var randoms = shuffle(arr.slice(0)); // array is cloned so it won't be destroyed
randoms.length = 4; // get 4 random elements
데모: http://jsbin.com/UHUHuqi/1/edit
다음에서 가져온 셔플 기능: https://stackoverflow.com/a/6274398/1669279
이런 문제를 해결할 수 있는 기능이 필요해서 공유합니다.
const getRandomItem = function(arr) {
return arr[Math.floor(Math.random() * arr.length)];
}
// original array
let arr = [4, 3, 1, 6, 9, 8, 5];
// number of random elements to get from arr
let n = 4;
let count = 0;
// new array to push random item in
let randomItems = []
do {
let item = getRandomItem(arr);
randomItems.push(item);
// update the original array and remove the recently pushed item
arr.splice(arr.indexOf(item), 1);
count++;
} while(count < n);
console.log(randomItems);
console.log(arr);
참고: 만약n = arr.length
그러면 기본적으로 당신은 배열을 섞는 것입니다.arr
그리고.randomItems
혼합된 배열을 반환합니다.
다음은 @Derek가 Python에서 포팅한 코드의 최적화된 버전이며, 추가된 파괴적(인플레이스) 옵션을 사용하여 사용할 수 있는 경우 가장 빠른 알고리즘을 제공합니다.그렇지 않으면 전체 복사본을 만들거나 대규모 어레이에서 요청된 소수의 항목에 대해 선택 기반 알고리즘으로 전환합니다.
// Chooses k unique random elements from pool.
function sample(pool, k, destructive) {
var n = pool.length;
if (k < 0 || k > n)
throw new RangeError("Sample larger than population or is negative");
if (destructive || n <= (k <= 5 ? 21 : 21 + Math.pow(4, Math.ceil(Math.log(k*3) / Math.log(4))))) {
if (!destructive)
pool = Array.prototype.slice.call(pool);
for (var i = 0; i < k; i++) { // invariant: non-selected at [i,n)
var j = i + Math.random() * (n - i) | 0;
var x = pool[i];
pool[i] = pool[j];
pool[j] = x;
}
pool.length = k; // truncate
return pool;
} else {
var selected = new Set();
while (selected.add(Math.random() * n | 0).size < k) {}
return Array.prototype.map.call(selected, i => pool[i]);
}
}
Derek의 구현과 비교하여, 첫 번째 알고리즘은 Firefox에서 훨씬 빠르지만 Chrome에서는 약간 느립니다. 하지만 이제는 파괴적인 옵션 - 가장 성능이 좋은 옵션을 가지고 있습니다.두 번째 알고리즘은 5-15% 더 빠릅니다.구체적인 숫자는 k와 n에 따라 다르며 아마도 새로운 브라우저 버전에서는 의미가 없을 것이기 때문에 저는 구체적인 숫자를 알려주지 않으려고 노력합니다.
알고리즘을 선택하는 휴리스틱은 Python 코드에서 비롯됩니다.가끔 느린 것을 선택하기도 하지만 그대로 두었습니다.JS에 최적화되어야 하지만 코너 케이스의 성능은 브라우저와 버전에 따라 다르기 때문에 복잡한 작업입니다.예를 들어 1000 또는 1050 중 20개를 선택하려고 하면 그에 따라 첫 번째 또는 두 번째 알고리즘으로 전환됩니다.이 경우 첫 번째 것은 크롬 80의 두 번째 것보다 2배 더 빠르지만 파이어폭스 74에서는 3배 더 느립니다.
중복이 있을 수 있는 샘플링:
const sample_with_duplicates = Array(sample_size).fill().map(() => items[~~(Math.random() * items.length)])
중복이 없는 샘플링:
const sample_without_duplicates = [...Array(items.length).keys()].sort(() => 0.5 - Math.random()).slice(0, sample_size).map(index => items[index]);
중복 항목이 없으면 전체 인덱스 배열을 먼저 정렬해야 하기 때문에 큰 용량의 중복 항목보다 속도가 상당히 느립니다.items
입력 배열.
중복이 없는 의 최대 크기는 <=입니다.items.length
이 바이올린을 확인하십시오. https://jsfiddle.net/doleron/5zw2vequ/30/
충분히 확보되거나 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;
}
교체 여부와 상관없이 어레이를 쉽게 샘플링할 수 있는 기능은 다음과 같습니다.
// 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]
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;
}
2019
이것은 라우리나스 말리샤우스카스가 대답한 것과 같습니다. 단지 요소가 고유하다는 것입니다(중복 없음).
var getMeRandomElements = function(sourceArray, neededElements) {
var result = [];
for (var i = 0; i < neededElements; i++) {
var index = Math.floor(Math.random() * sourceArray.length);
result.push(sourceArray[index]);
sourceArray.splice(index, 1);
}
return result;
}
이제 "jQuery로 여러 랜덤 요소를 가져오는 방법"이라는 원래 질문에 답하겠습니다.
var getMeRandomElements = function(sourceArray, neededElements) {
var result = [];
for (var i = 0; i < neededElements; i++) {
var index = Math.floor(Math.random() * sourceArray.length);
result.push(sourceArray[index]);
sourceArray.splice(index, 1);
}
return result;
}
var $set = $('.someClass');// <<<<< change this please
var allIndexes = [];
for(var i = 0; i < $set.length; ++i) {
allIndexes.push(i);
}
var totalRandom = 4;// <<<<< change this please
var randomIndexes = getMeRandomElements(allIndexes, totalRandom);
var $randomElements = null;
for(var i = 0; i < randomIndexes.length; ++i) {
var randomIndex = randomIndexes[i];
if($randomElements === null) {
$randomElements = $set.eq(randomIndex);
} else {
$randomElements.add($set.eq(randomIndex));
}
}
// $randomElements is ready
$randomElements.css('backgroundColor', 'red');
const items = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1, 2, 3, 4, 5];
const fetchRandomArray = ({pool=[], limit=1})=>{
let query = []
let selectedIndices = {}
while(query.length < limit){
const index = Math.floor(Math.random()*pool.length)
if(typeof(selectedIndices[index])==='undefined'){
query.push(items[index])
selectedIndices[index] = index
}
}
console.log(fetchRandomArray({pool:items, limit:10})
실제로 정렬할 필요가 없으며 랜덤 하위 어레이 길이만 생성하면 됩니다.
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)
다음은 가장 정확한 답이며 랜덤 + 고유 요소를 제공합니다.
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
items.sys((() => (수학.랜덤() > 0.5 ? 1 : -1)).슬라이스(0, 카운트);
언급URL : https://stackoverflow.com/questions/19269545/how-to-get-a-number-of-random-elements-from-an-array
'sourcecode' 카테고리의 다른 글
sql에서 값을 동적으로 변경하려고 합니다. (0) | 2023.08.12 |
---|---|
Git Stash 팝업 삭제 (0) | 2023.08.12 |
크롬 확장에서 jQuery를 어떻게 사용합니까? (0) | 2023.08.12 |
Spring MVC에서 페이지화 구현 방법 3 (0) | 2023.08.12 |
스핑크스SE로 MVA를 검색하려면 어떻게 해야 합니까? (0) | 2023.08.12 |