Bagaimana cara mendapatkan sejumlah elemen acak dari sebuah array?

106

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?

Shyam Dixit
sumber
5
Jalankan saja beberapa kali?
Bergi
2
Dari pernyataan ini dapatkah kita melakukan ini ?? Loop menghasilkan duplikat.
Shyam Dixit
1
Dari pernyataan yang tepat Anda tidak bisa mendapatkan lebih dari satu elemen.
Sébastien
1
Ah, Anda seharusnya mengatakan bahwa Anda tidak menginginkan duplikat. Lalu centang Nomor acak unik di O (1)? dan jawaban saya di Hasilkan nomor unik dalam jangkauan (0 - X), menyimpan riwayat untuk mencegah duplikat
Bergi
1
Saya membuat JsPerf untuk menguji beberapa solusi di sini. @ Bergi tampaknya menjadi yang terbaik secara umum, sementara milik saya bekerja lebih baik jika Anda membutuhkan banyak elemen dari array. jsperf.com/k-random-elements-from-array
Tibos

Jawaban:

108

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;
}
Bergi
sumber
13
Halo, saya hanya ingin mengatakan bahwa saya menghabiskan waktu sekitar sepuluh menit untuk menghargai keindahan algoritma ini.
Prajeeth Emanuel
Saya akan menyarankan menggunakan implementasi Python jika Anda menginginkan
Derek 朕 會 功夫
@Derek 朕 會 功夫 Ah, pintar, itu bekerja jauh lebih baik untuk sampel kecil dari rentang besar memang. Terutama dengan menggunakan ES6 Set(yang tidak tersedia di '13: - /)
Bergi
@AlexWhite Terima kasih atas umpan baliknya, saya tidak percaya bug ini menghindari semua orang selama bertahun-tahun. Tetap. Anda seharusnya memberi komentar, bukan menyarankan pengeditan.
Bergi
2
@ cbdev420 Ya, ini hanya pengocokan nelayan (sebagian)
Bergi
196

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 :

Abdennour TOUMI
sumber
23
Sangat bagus! Satu kapal juga tentu saja memungkinkan:let random = array.sort(() => .5 - Math.random()).slice(0,n)
unitario
1
Jenius! Elegan, pendek dan sederhana, cepat, menggunakan fungsionalitas bawaan.
Vlad
37
Itu bagus, tapi jauh dari kata acak. Item pertama memiliki lebih banyak peluang untuk dipilih daripada yang terakhir. Lihat di sini alasannya: stackoverflow.com/a/18650169/1325646
pomber
Ini tidak mempertahankan jenis array asli
almathie
4
Luar biasa! jika Anda ingin menjaga agar array tetap utuh, Anda dapat mengubah baris pertama seperti ini: const shuffled = [... array] .sort (() => 0.5 - Math.random ());
Yair Levy
12

Porting .sampledari 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:

  • setsizediatur berdasarkan karakteristik dalam Python untuk efisiensi. Meski belum disesuaikan untuk JavaScript, algoritme tersebut akan tetap berfungsi seperti yang diharapkan.
  • Beberapa jawaban lain yang dijelaskan di halaman ini tidak aman menurut spesifikasi ECMAScript karena penyalahgunaan Array.prototype.sort. Namun algoritma ini dijamin akan berhenti dalam waktu yang terbatas.
  • Untuk browser lama yang belum Setdiimplementasikan, set dapat diganti dengan Arraydan .has(j)diganti dengan .indexOf(j) > -1.

Performa terhadap jawaban yang diterima:

Derek 朕 會 功夫
sumber
Saya telah memposting versi yang dioptimalkan dari kode ini di bawah. Juga mengoreksi parameter acak yang salah di algo kedua di posting Anda. Saya bertanya-tanya berapa banyak orang yang menggunakan versi bias sebelumnya dalam produksi, harap tidak ada yang kritis.
pengguna
11

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)

pomber
sumber
Bisakah kita mendapatkan penjelasan yang lebih baik tentang cara kerjanya?
Qasim
10

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.

Laurynas Mališauskas
sumber
Jawaban yang bagus! Lihat jawaban saya, salin kode Anda, dan tambahkan fungsi "hanya elemen unik".
evilReiko
1
Fungsi ini dapat mengembalikan elemen yang sama sourceArraybeberapa kali.
Sampo
6

Sintaks ES6

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

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);

Rory McCrossan
sumber
1
Dalam pernyataan items.splice (idx, 1) mengapa Anda menggunakan '1' ini? sambatan??
Shyam Dixit
2
Shyam Dixit , menurut dokumentasi MDN yang 1adalah deleteCountmenunjukkan jumlah elemen array lama untuk menghapus. (Kebetulan, saya mengurangi dua baris terakhir menjadi newItems.push(items.splice(idx, 1)[0])).
Kurt Peek
5

lodash ( https://lodash.com/ ) _.sampledan_.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]
nodejh
sumber
Apa _? Ini bukan objek Javascript standar.
vanowm
2
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();
lo.fish の archywillhe
sumber
2

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);
Daniel Birowsky Popeski
sumber
2


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));

MAMY Sébastien
sumber
Saya menyadari bahwa fungsinya tidak menghasilkan semua kemungkinan larik acak dari larik sumber. Di dunia lain, hasilnya tidak seacak yang seharusnya ... ada ide perbaikan?
MAMY Sébastien
dimana _shufflefungsinya?
vanowm
Juga, ketika size >= ar.length, hasilnya akansize-1
idleberg
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

Tibos
sumber
Itu tergantung pada persentase item acak yang dibutuhkan dari array. Jika Anda menginginkan 9 elemen acak dari 10 elemen array, itu pasti akan lebih cepat untuk mengocok daripada mengekstrak 9 elemen acak satu demi satu. Jika persentase kegunaannya kurang dari 50%, maka ada kasus penggunaan di mana solusi ini adalah yang tercepat. Kalau tidak, saya akui bahwa itu tidak berguna :).
Tibos
Maksud saya, mengacak 9 elemen lebih cepat daripada mengacak 10 elemen. Btw Saya yakin OP tidak ingin menghancurkan input array-nya…
Bergi
Saya rasa saya tidak mengerti bagaimana mengocok 9 elemen membantu dalam masalah ini. Saya sadar bahwa jika Anda menginginkan lebih dari setengah larik, Anda cukup mengiris elemen acak sampai Anda tetap dengan berapa banyak yang Anda inginkan kemudian mengocok untuk mendapatkan urutan acak. Apakah ada yang saya lewatkan? PS: Memperbaiki kerusakan array, terima kasih.
Tibos
Tidak ada hubungannya dengan "setengah dari". Anda hanya perlu melakukan pekerjaan sebanyak elemen yang ingin Anda dapatkan kembali, Anda tidak perlu memperlakukan keseluruhan array pada titik mana pun. Kode Anda saat ini memiliki kompleksitas O(n+k)(n elemen dalam array, Anda menginginkan k dari mereka) sementara O(k)akan memungkinkan (dan optimal).
Bergi
1
Oke, kode Anda memiliki lebih banyak like O(2n)yang dapat dikurangi menjadi O(n+k)jika Anda mengubah loop menjadi while (counter-- > len-k)dan mengambil elemen terakhir (bukan yang pertama) kdarinya. Memang splice(i, 1)tidak punya O(1), tapi O(k)solusinya masih memungkinkan (lihat jawaban saya). O(n+k)Sayangnya, kompleksitas ruang tetap ada , tetapi bisa menjadi O(2k)tergantung pada implementasi larik jarang.
Bergi
1

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.lengthkemudian pada dasarnya Anda mengocok array arrdan randomItemsmengembalikan array yang diacak.

Demo

Penyimpanan Lenovo
sumber
1

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

haouarin
sumber
1

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.

pengguna
sumber
Terjadi kesalahan log(k*3, 4)karena JS tidak memiliki baseargumennya. Haruslog(k*3)/log(4)
disfated
Juga, saya melihat sisi negatif di bagian di mana Anda menggunakan kembali poolsebagai file result. Karena Anda memotongnya pool, ini tidak dapat digunakan sebagai sumber pengambilan sampel lagi dan lain kali Anda menggunakannya, sampleAnda harus membuat ulang pooldari 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.
disfated
@puas, makasih, sudah diperbaiki logdi kode saya dan Derek. Sedangkan untuk menggunakan kembali pool, jangan aktifkan destructiveopsi, maka poolargumen dibayangi dengan salinan.
pengguna
Apakah .call(selected, i => population[i]);seharusnya .call(selected, i => pool[i]);?
pengguna-124812948
@ user-124812948: ya, terima kasih, sudah diperbaiki.
pengguna
0

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;
}

Aleksey Yaremenko
sumber
Selamat datang di SO! Saat memposting jawaban, penting untuk menyebutkan cara kerja kode Anda dan / atau cara memecahkan masalah OP :)
Joel
0

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');
evilReiko
sumber
0

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]

Jared Wilber
sumber
0
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;
}
Manoj Rana
sumber
0

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)]);
DedaDev
sumber
Anda tidak memastikan dua item tidak terulang.
Valery
-2

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
Nivesh Saharan
sumber
Ada sesuatu yang aneh terjadi dengan pengacakan yang satu ini - saya mendapatkan hasil yang sama muncul 6 dari 9 percobaan (dengan n 8 dan ukuran array 148). Anda mungkin berpikir untuk beralih ke metode Fisher-Yates ; itulah yang saya lakukan dan sekarang bekerja jauh lebih baik.
asetniop
Ini membutuhkan waktu kuadrat karena melakukan pemeriksaan keunikan yang buruk dan tidak memiliki kesempatan yang sama untuk memilih setiap item karena diurutkan dengan perbandingan acak.
Ry-
-2

items.sort (() => (Math.random ()> 0.5? 1: -1)). slice (0, count);

Yauheni Charniauski
sumber
Menghasilkan distribusi yang sedikit tidak merata.
Patrolin