Saya sedang mengerjakan 'cara mengakses elemen secara acak dari array di javascript'. Saya menemukan banyak tautan tentang ini. Suka: Dapatkan item acak dari array JavaScript
var item = items[Math.floor(Math.random()*items.length)];
Tetapi dalam hal ini, kita hanya dapat memilih satu item dari array. Jika kita menginginkan lebih dari satu elemen, lalu bagaimana kita bisa mencapai ini? Bagaimana kita bisa mendapatkan lebih dari satu elemen dari sebuah array?
javascript
jquery
html
arrays
Shyam Dixit
sumber
sumber
Jawaban:
Coba fungsi non-destruktif (dan cepat ) ini:
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; }
sumber
Set
(yang tidak tersedia di '13: - /)Hanya dua baris:
// 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 :
sumber
let random = array.sort(() => .5 - Math.random()).slice(0,n)
Ada solusi unik satu baris di sini
array.sort(() => Math.random() - Math.random()).slice(0, n)
sumber
Porting
.sample
dari pustaka standar 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; }
Implementasi porting dari Lib / random.py .
Catatan:
setsize
diatur berdasarkan karakteristik dalam Python untuk efisiensi. Meski belum disesuaikan untuk JavaScript, algoritme tersebut akan tetap berfungsi seperti yang diharapkan.Array.prototype.sort
. Namun algoritma ini dijamin akan berhenti dalam waktu yang terbatas.Set
diimplementasikan, set dapat diganti denganArray
dan.has(j)
diganti dengan.indexOf(j) > -1
.Performa terhadap jawaban yang diterima:
sumber
Mendapatkan 5 item acak tanpa mengubah array asli:
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);
(Jangan gunakan ini untuk daftar besar)
sumber
buat fungsi yang melakukan itu:
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; }
Anda juga harus memeriksa apakah sourceArray memiliki cukup elemen untuk dikembalikan. dan jika Anda ingin elemen unik dikembalikan, Anda harus menghapus elemen yang dipilih dari sourceArray.
sumber
sourceArray
beberapa kali.Sintaks ES6
const pickRandom = (arr,count) => { let _arr = [...arr]; return[...Array(count)].map( ()=> _arr.splice(Math.floor(Math.random() * _arr.length), 1)[0] ); }
sumber
Jika Anda ingin mendapatkan item secara acak dari array dalam satu lingkaran tanpa pengulangan, Anda dapat menghapus item yang dipilih dari array dengan
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);
sumber
1
adalahdeleteCount
menunjukkan jumlah elemen array lama untuk menghapus. (Kebetulan, saya mengurangi dua baris terakhir menjadinewItems.push(items.splice(idx, 1)[0])
).lodash ( https://lodash.com/ )
_.sample
dan_.sampleSize
.Mendapat satu atau n elemen acak pada kunci unik dari koleksi hingga ukuran koleksi.
_.sample([1, 2, 3, 4]); // => 2 _.sampleSize([1, 2, 3], 2); // => [3, 1] _.sampleSize([1, 2, 3], 3); // => [2, 3, 1]
sumber
_
? Ini bukan objek Javascript standar.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();
sumber
Ini versi yang diketik dengan baik. Itu tidak gagal. Mengembalikan larik yang diacak jika ukuran sampel lebih besar dari panjang larik asli.
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);
sumber
Gaya pemrograman fungsional non destruktif 2020 , bekerja dalam konteks yang tidak berubah.
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));
sumber
_shuffle
fungsinya?size >= ar.length
, hasilnya akansize-1
EDIT : Solusi ini lebih lambat daripada yang lain yang disajikan di sini (yang menghubungkan array sumber) jika Anda hanya ingin mendapatkan beberapa elemen. Kecepatan solusi ini hanya bergantung pada jumlah elemen dalam larik asli, sedangkan kecepatan solusi penyambungan bergantung pada jumlah elemen yang diperlukan dalam larik keluaran.
Jika Anda menginginkan elemen acak yang tidak berulang, Anda dapat mengocok array Anda lalu mendapatkan sebanyak yang Anda inginkan:
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
DEMO: http://jsbin.com/UHUHuqi/1/edit
Fungsi acak diambil dari sini: https://stackoverflow.com/a/6274398/1669279
sumber
O(n+k)
(n elemen dalam array, Anda menginginkan k dari mereka) sementaraO(k)
akan memungkinkan (dan optimal).O(2n)
yang dapat dikurangi menjadiO(n+k)
jika Anda mengubah loop menjadiwhile (counter-- > len-k)
dan mengambil elemen terakhir (bukan yang pertama)k
darinya. Memangsplice(i, 1)
tidak punyaO(1)
, tapiO(k)
solusinya masih memungkinkan (lihat jawaban saya).O(n+k)
Sayangnya, kompleksitas ruang tetap ada , tetapi bisa menjadiO(2k)
tergantung pada implementasi larik jarang.Saya membutuhkan fungsi untuk menyelesaikan masalah semacam ini jadi saya membagikannya di sini.
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);
Catatan: jika
n = arr.length
kemudian pada dasarnya Anda mengocok arrayarr
danrandomItems
mengembalikan array yang diacak.Demo
sumber
Dalam jawaban ini, saya ingin berbagi dengan Anda pengujian bahwa saya harus mengetahui metode terbaik yang memberikan peluang yang sama untuk semua elemen untuk memiliki subarray acak.
Metode 01
array.sort(() => Math.random() - Math.random()).slice(0, n)
menggunakan metode ini, beberapa elemen memiliki peluang lebih tinggi dibandingkan dengan yang lain.
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)
Metode 2
Dengan menggunakan metode ini, elemen memiliki probabilitas yang sama:
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)
Jawaban yang benar diposting di tautan berikut: https://stackoverflow.com/a/46545530/3811640
sumber
Berikut adalah versi optimal dari kode yang di- porting dari Python oleh @Derek, dengan tambahan opsi destruktif (di tempat) yang menjadikannya algoritme tercepat jika Anda dapat menggunakannya. Jika tidak, ia akan membuat salinan lengkap atau, untuk sejumlah kecil item yang diminta dari larik besar, beralih ke algoritme berbasis pilihan.
// 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]); } }
Dibandingkan dengan implementasi Derek, algoritma pertama jauh lebih cepat di Firefox sementara sedikit lebih lambat di Chrome, meskipun sekarang ia memiliki opsi destruktif - yang paling berkinerja. Algoritme kedua hanya 5-15% lebih cepat. Saya mencoba untuk tidak memberikan angka konkret karena jumlahnya bervariasi tergantung pada k dan n dan mungkin tidak akan berarti apa-apa di masa depan dengan versi browser baru.
Heuristik yang membuat pilihan antara algoritme berasal dari kode Python. Saya membiarkannya apa adanya, meskipun terkadang memilih yang lebih lambat. Ini harus dioptimalkan untuk JS, tetapi ini adalah tugas yang kompleks karena kinerja kasus sudut bergantung pada browser dan versinya. Misalnya, ketika Anda mencoba memilih 20 dari 1000 atau 1050, itu akan beralih ke algoritma pertama atau kedua yang sesuai. Dalam hal ini, yang pertama berjalan 2x lebih cepat daripada yang kedua di Chrome 80 tetapi 3x lebih lambat di Firefox 74.
sumber
log(k*3, 4)
karena JS tidak memilikibase
argumennya. Haruslog(k*3)/log(4)
pool
sebagai fileresult
. Karena Anda memotongnyapool
, ini tidak dapat digunakan sebagai sumber pengambilan sampel lagi dan lain kali Anda menggunakannya,sample
Anda harus membuat ulangpool
dari beberapa sumber lagi. Penerapan Derek hanya mengacak kumpulan, sehingga dapat digunakan kembali dengan sempurna untuk pengambilan sampel tanpa membuat ulang. Dan saya yakin ini adalah kasus penggunaan yang paling sering.log
di kode saya dan Derek. Sedangkan untuk menggunakan kembalipool
, jangan aktifkandestructive
opsi, makapool
argumen dibayangi dengan salinan..call(selected, i => population[i]);
seharusnya.call(selected, i => pool[i]);
?Ia mengekstrak elemen acak dari srcArray satu per satu saat sudah cukup atau tidak ada lagi elemen di srcArray yang tersisa untuk diekstraksi. Cepat dan andal.
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; }
sumber
2019
Ini sama dengan jawaban Laurynas Mališauskas , hanya saja elemennya unik (tidak ada duplikat).
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; }
Sekarang untuk menjawab pertanyaan asli "Bagaimana cara mendapatkan beberapa elemen acak dengan jQuery", ini dia:
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');
sumber
Berikut adalah fungsi yang saya gunakan yang memungkinkan Anda untuk dengan mudah mengambil sampel array dengan atau tanpa penggantian:
// 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; };
Menggunakannya sederhana:
Tanpa Penggantian (perilaku default)
randomSample([1, 2, 3], 2)
mungkin kembali[2, 1]
Dengan Penggantian
randomSample([1, 2, 3, 4, 5, 6], 4)
mungkin kembali[2, 3, 3, 2]
sumber
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; }
sumber
Saya tidak percaya tidak ada yang tidak menyebutkan metode ini, cukup bersih dan lurus ke depan.
const getRnd = (a, n) => new Array(n).fill(null).map(() => a[Math.floor(Math.random() * a.length)]);
sumber
Ini adalah jawaban yang paling benar dan akan memberi Anda elemen Acak + Unik.
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
sumber
items.sort (() => (Math.random ()> 0.5? 1: -1)). slice (0, count);
sumber