배열에서 n 개의 요소를 무작위로 얻는 방법
나는 '자바 펼쳐의 배열에서 무작위로 요소에 액세스하는 방법'을 연구하고 있습니다. 이것에 관한 많은 링크를 찾았습니다. 좋아요 : JavaScript 배열에서 임의의 항목 가져 오기
var item = items[Math.floor(Math.random()*items.length)];
질문 : 여기서는 배열에서 하나의 항목 만 선택할 수 있습니다. 하나 이상의 요소를 어떻게 달성 할 수 있습니까?이 문장에서 배열에서 하나 이상의 요소를 얻을 수있는 방법을 알려주세요.
다음과 같은 비파괴 ( 빠른 ) 기능을 중지합니다 .
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;
}
두 줄 :
// 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);
스템 :
다음과 같은 기능을 만듭니다.
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에 반환 할 요소가 있는지 확인해야합니다. 고유 한 한 요소를 반환 할 항목 소스 배열에서 선택한 요소를 제거해야합니다.
원래 배열을 변경하지 않고 무작위 항목 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, 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 - i) | 0;
while(selected.has(j)){
j = Math.random() * (n - i) | 0;
}
selected.add(j);
result[i] = population[j];
}
}
return result;
}
Lib / random.py 에서 이식 된 구현 입니다.
메모 :
setsize
효율성을 위해 Python의 특성을 기반으로 설정됩니다. JavaScript에 맞게 조정되지 않은 알고리즘은 여전히 예상대로 작동합니다.- 이 페이지에 설명 된 다른 답변은 .NET Framework의 오용으로 인해 ECMAScript 사양에 따라 안전하지 않습니다
Array.prototype.sort
. 그러나이 알고리즘은 유한 한 시간 돌연변이 종료됩니다. - 하지 않는 이전 브라우저의
Set
구현, 설정은 대체 할 수Array
및.has(j)
교체.indexOf(j) > -1
.
허용 된 답변에 대한 성능 :
- https://jsperf.com/pick-random-elements-from-an-array
- 성능 차이는 Safari에서 가장 많이 먹을 것입니다.
ES6 구문
const pickRandom = (arr,count) => {
let _arr = [...arr];
return[...Array(count)].map( ()=> _arr.splice(Math.floor(Math.random() * _arr.length), 1)[0] );
}
반복 항목없이 루프에서 배열에서 항목을 무작위로 가져 오기 다음을 사용하여 배열에서 선택을 제거합니다 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);
}
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 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
반환합니다.
여기에 잘 입력 된 버전이 있습니다. 실패하지 않습니다. 샘플 크기가 원래 배열의 길이보다 큰 경우 셔플 된 배열을 반환합니다.
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);
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;
}
2019 년
이것은 Laurynas Mališauskas의 답변 과 동일하지만 요소가 고유 한 점만 있습니다 ( 중복 없음).
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');
다음은 교체 여부에 관계없이 배열을 쉽게 샘플링 할 수있는 함수입니다.
// 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;
}
여기에 한 줄 고유 한 솔루션이 있습니다.
array.sort(() => {Math.random() - Math.random()}).slice(0, n)
여기에 가장 정답이 제공되며 Random + Unique 요소를 제공합니다.
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
참고 URL : https://stackoverflow.com/questions/19269545/how-to-get-n-no-elements-randomly-from-an-array
'ProgramingTip' 카테고리의 다른 글
Unix에서 재귀 적 mkdir () 시스템 호출 (0) | 2020.11.22 |
---|---|
Ruby에서 노드를 상수로 변환하는 방법은 무엇입니까? (0) | 2020.11.22 |
Visual Studio의 기본 네임 명명 규칙과 싸움을 중지해야합니까? (0) | 2020.11.21 |
Android : Proguard에 권장되는 구성은 무엇입니까? (0) | 2020.11.21 |
프로그래밍 기술을 향상시키기위한 아주 작은 프로그램? (0) | 2020.11.21 |