Làm thế nào để lấy một số phần tử ngẫu nhiên từ một mảng?


103

Tôi đang làm việc về 'cách truy cập các phần tử một cách ngẫu nhiên từ một mảng trong javascript'. Tôi tìm thấy nhiều liên kết liên quan đến điều này. Như: Nhận mục ngẫu nhiên từ mảng JavaScript

var item = items[Math.floor(Math.random()*items.length)];

Nhưng trong điều này, chúng ta chỉ có thể chọn một mục từ mảng. Nếu chúng ta muốn có nhiều hơn một yếu tố thì làm thế nào chúng ta có thể đạt được điều này? Làm cách nào chúng ta có thể lấy nhiều hơn một phần tử từ một mảng?


5
Chỉ cần thực hiện nó nhiều lần?
Bergi

2
Từ câu lệnh này chúng ta có thể làm được điều này không ?? Vòng lặp tạo ra các bản sao.
Shyam Dixit

1
Từ tuyên bố chính xác đó, bạn không thể nhận được nhiều hơn một phần tử.
Sébastien

1
Ah, bạn nên nói rằng bạn muốn không có bản sao. Sau đó kiểm tra Số ngẫu nhiên duy nhất trong O (1)? và câu trả lời của tôi tại Generate số duy nhất trong phạm vi (0 - X), giữ một lịch sử để ngăn chặn bản sao
Bergi

1
Tôi đã tạo một JsPerf để kiểm tra một số giải pháp ở đây. Nói chung, @ Bergi's có vẻ là tốt nhất, trong khi của tôi hoạt động tốt hơn nếu bạn cần nhiều phần tử từ mảng. jsperf.com/k-random-elements-from-array
Tibos

Câu trả lời:


97

Hãy thử chức năng không phá hủy (và nhanh ) này:

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

10
Này anh bạn, tôi chỉ muốn nói rằng tôi đã dành khoảng mười phút để đánh giá cao vẻ đẹp của thuật toán này.
Prajeeth Emanuel

Tôi sẽ đề xuất sử dụng triển khai Python nếu bạn muốn tăng tốc: jsperf.com/pick-random-elements-from-an-array
Derek 朕 會 功夫

@Derek 朕 會 功夫 Ah, thật thông minh, điều đó thực sự hoạt động tốt hơn nhiều đối với các mẫu nhỏ từ phạm vi lớn. Đặc biệt với việc sử dụng ES6 Set(không có trong '13: - /)
Bergi

@AlexWhite Cảm ơn bạn đã phản hồi, tôi không thể tin rằng lỗi này đã trốn tránh mọi người trong nhiều năm. Đã sửa. Tuy nhiên, bạn nên đăng một bình luận, không được đề xuất chỉnh sửa.
Bergi

2
@ cbdev420 Vâng, nó chỉ là một (một phần) Fisher-Yates xáo trộn
Bergi

189

Chỉ hai dòng:

// 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 :


22
Rất đẹp! Tất nhiên cũng có thể có một lớp lót:let random = array.sort(() => .5 - Math.random()).slice(0,n)
unitario

1
Thiên tài! Thanh lịch, ngắn gọn và đơn giản, nhanh chóng, sử dụng chức năng tích hợp.
Vlad

35
Nó hay, nhưng không phải là ngẫu nhiên. Vật phẩm đầu tiên có nhiều cơ hội được chọn hơn vật phẩm cuối cùng. Xem tại sao ở đây: stackoverflow.com/a/18650169/1325646
pomber

Điều này không bảo toàn loại của mảng ban đầu
almathie

3
Kinh ngạc! Nếu bạn muốn giữ nguyên mảng, bạn chỉ cần thay đổi dòng đầu tiên như sau: const shuffled = [... array] .sort (() => 0.5 - Math.random ());
Yair Levy


12

Chuyển .sampletừ thư viện chuẩn 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;
}

Triển khai được chuyển từ Lib / random.py .

Ghi chú:

  • setsizeđược đặt dựa trên các đặc điểm trong Python để mang lại hiệu quả. Mặc dù nó chưa được điều chỉnh cho JavaScript, thuật toán vẫn sẽ hoạt động như mong đợi.
  • Một số câu trả lời khác được mô tả trong trang này không an toàn theo đặc điểm kỹ thuật ECMAScript do việc sử dụng sai Array.prototype.sort. Tuy nhiên, thuật toán này được đảm bảo kết thúc trong thời gian hữu hạn.
  • Đối với các trình duyệt cũ hơn chưa được Settriển khai, tập hợp có thể được thay thế bằng một Array.has(j)thay thế bằng .indexOf(j) > -1.

Hiệu suất so với câu trả lời được chấp nhận:


Tôi đã đăng một phiên bản được tối ưu hóa của mã này bên dưới. Đồng thời sửa thông số ngẫu nhiên sai trong bí danh thứ hai trong bài đăng của bạn. Tôi tự hỏi có bao nhiêu người đang sử dụng phiên bản thiên vị trước trong sản xuất, hy vọng không có gì quan trọng.
người dùng

11

Nhận 5 mục ngẫu nhiên mà không thay đổi mảng ban đầu:

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

(Không sử dụng cái này cho các danh sách lớn)


Chúng tôi có thể có một lời giải thích tốt hơn về cách hoạt động của điều này?
Qasim

10

tạo một funcion để thực hiện điều đó:

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

bạn cũng nên kiểm tra xem sourceArray có đủ các phần tử để trả về hay không. và nếu bạn muốn các phần tử duy nhất được trả về, bạn nên xóa phần tử đã chọn khỏi sourceArray.


Câu trả lời tốt! Hãy xem câu trả lời của tôi, sao chép mã của bạn và thêm chức năng "chỉ các yếu tố duy nhất".
evilReiko

1
Hàm này có thể trả về cùng một phần tử sourceArraynhiều lần.
Sampo

6

Cú pháp ES6

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

4

Nếu bạn muốn lấy ngẫu nhiên các mục từ mảng trong một vòng lặp mà không lặp lại, bạn có thể xóa mục đã chọn khỏi mảng bằng 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);


1
Trong câu lệnh items.splice (idx, 1) tại sao bạn sử dụng '1' này? mối nối ??
Shyam Dixit

2
Shyam Dixit , theo các tài liệu MDN sự 1deleteCountchỉ số của phần tử mảng cũ để loại bỏ. (Ngẫu nhiên, tôi giảm hai dòng cuối cùng thành newItems.push(items.splice(idx, 1)[0])).
Kurt Peek

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

2

Đây là một phiên bản được đánh máy độc đáo. Nó không thất bại. Trả về mảng xáo trộn nếu kích thước mẫu lớn hơn độ dài của mảng ban đầu.

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

2

lodash ( https://lodash.com/ ) _.sample_.sampleSize.

Nhận một hoặc n phần tử ngẫu nhiên tại các khóa duy nhất từ ​​bộ sưu tập cho đến kích thước của bộ sưu tập.

_.sample([1, 2, 3, 4]);
// => 2

_.sampleSize([1, 2, 3], 2);
// => [3, 1]
 
_.sampleSize([1, 2, 3], 4);
// => [2, 3, 1]

_gì? Nó không phải là một đối tượng Javascript chuẩn.
vanowm

Xin chào @vanowm, đó là lodash lodash.com
nodejh

1

CHỈNH SỬA : Giải pháp này chậm hơn các giải pháp khác được trình bày ở đây (nối mảng nguồn) nếu bạn chỉ muốn lấy một vài phần tử. Tốc độ của giải pháp này chỉ phụ thuộc vào số phần tử trong mảng ban đầu, trong khi tốc độ của giải pháp nối phụ thuộc vào số lượng phần tử được yêu cầu trong mảng đầu ra.

Nếu bạn muốn các phần tử ngẫu nhiên không lặp lại, bạn có thể xáo trộn mảng của mình, sau đó chỉ lấy bao nhiêu tùy thích:

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

Chức năng xáo trộn lấy từ đây: https://stackoverflow.com/a/6274398/1669279


Điều đó phụ thuộc vào tỷ lệ các mục ngẫu nhiên được yêu cầu từ mảng. Nếu bạn muốn có 9 phần tử ngẫu nhiên từ một mảng 10 phần tử, chắc chắn việc xáo trộn sẽ nhanh hơn là trích xuất 9 phần tử ngẫu nhiên lần lượt. Nếu tỷ lệ phần trăm này hữu ích nhỏ hơn 50%, thì có những trường hợp sử dụng mà giải pháp này là nhanh nhất. Nếu không, tôi thừa nhận rằng nó là vô ích :).
Tibos

Ý tôi là xáo trộn 9 phần tử sẽ nhanh hơn xáo trộn 10 phần tử. Btw, tôi tin chắc rằng OP không muốn phá hủy mảng đầu vào của mình…
Bergi

Tôi không nghĩ rằng tôi hiểu cách xáo trộn 9 yếu tố giúp ích trong vấn đề này. Tôi biết rằng nếu bạn muốn nhiều hơn một nửa mảng, bạn có thể chỉ cần cắt ra các phần tử ngẫu nhiên cho đến khi bạn vẫn còn số lượng bạn muốn sau đó xáo trộn để có được một thứ tự ngẫu nhiên. Có điều gì tôi bỏ lỡ không? PS: Đã sửa lỗi phá hủy mảng, cảm ơn.
Tibos

Nó không phải làm bất cứ điều gì với "một nửa của". Bạn chỉ cần thực hiện nhiều công việc như các phần tử mà bạn muốn lấy lại, bạn không cần phải xử lý toàn bộ mảng ở bất kỳ điểm nào. Mã hiện tại của bạn có độ phức tạp là O(n+k)(n phần tử trong mảng, bạn muốn k trong số chúng) trong khi O(k)có thể (và tối ưu).
Bergi

1
Được rồi, mã của bạn có nhiều điểm giống hơn O(2n)có thể được giảm xuống O(n+k)nếu bạn thay đổi vòng lặp thành while (counter-- > len-k)và lấy các phần tử cuối cùng (thay vì đầu tiên) kra khỏi nó. Thật vậy splice(i, 1)không có O(1), nhưng một O(k)giải pháp vẫn có thể (xem câu trả lời của tôi). Tuy nhiên, độ phức tạp không gian vẫn ở mức O(n+k)không may, nhưng có thể trở nên O(2k)phụ thuộc vào việc triển khai mảng thưa thớt.
Bergi

1

Tôi cần một chức năng để giải quyết loại vấn đề này nên tôi đang chia sẻ nó ở đây.

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

Lưu ý: nếu n = arr.lengthsau đó về cơ bản bạn đang xáo trộn mảng arrrandomItemstrả về mảng đã xáo trộn đó.

Bản giới thiệu


1

Trong câu trả lời này, tôi muốn chia sẻ với bạn bài kiểm tra rằng tôi phải biết phương pháp tốt nhất mang lại cơ hội như nhau cho tất cả các phần tử có một mảng con ngẫu nhiên.

Phương pháp 01

array.sort(() => Math.random() - Math.random()).slice(0, n)

sử dụng phương pháp này, một số yếu tố có cơ hội cao hơn so với những yếu tố khác.

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)

Phương pháp 2

Sử dụng phương pháp này, các phần tử có cùng xác suất:

 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)

Câu trả lời chính xác được đăng trong liên kết sau: https://stackoverflow.com/a/46545530/3811640


1

Đây là phiên bản được tối ưu hóa của được @Derek chuyển từ Python, với tùy chọn phá hủy (tại chỗ) được bổ sung giúp nó trở thành thuật toán nhanh nhất có thể nếu bạn có thể sử dụng nó. Nếu không, nó sẽ tạo một bản sao đầy đủ hoặc đối với một số lượng nhỏ các mục được yêu cầu từ một mảng lớn, sẽ chuyển sang thuật toán dựa trên lựa chọn.

// 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, 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 => population[i]);
    }
}

So với cách triển khai của Derek, thuật toán đầu tiên nhanh hơn nhiều trong Firefox trong khi chậm hơn một chút trong Chrome, mặc dù bây giờ nó có tùy chọn hủy diệt - thuật toán hiệu quả nhất. Thuật toán thứ hai chỉ đơn giản là nhanh hơn 5-15%. Tôi cố gắng không đưa ra bất kỳ con số cụ thể nào vì chúng khác nhau tùy thuộc vào k và n và có lẽ sẽ không có ý nghĩa gì trong tương lai với các phiên bản trình duyệt mới.

Heuristic tạo ra sự lựa chọn giữa các thuật toán bắt nguồn từ mã Python. Tôi đã để nguyên như vậy, mặc dù đôi khi nó chọn cái chậm hơn. Nó nên được tối ưu hóa cho JS, nhưng đó là một nhiệm vụ phức tạp vì hiệu suất của các trường hợp góc phụ thuộc vào trình duyệt và phiên bản của chúng. Ví dụ: khi bạn cố gắng chọn 20 trong số 1000 hoặc 1050, nó sẽ chuyển sang thuật toán thứ nhất hoặc thứ hai cho phù hợp. Trong trường hợp này, cái đầu tiên chạy nhanh hơn 2 lần so với cái thứ hai trong Chrome 80 nhưng chậm hơn 3 lần trong Firefox 74.


Có lỗi log(k*3, 4)vì JS không có baseđối số. Nênlog(k*3)/log(4)
bỏ

Ngoài ra, tôi thấy một nhược điểm ở phần mà bạn sử dụng lại poolnhư một result. Vì bạn cắt ngắn poolnó không thể được sử dụng như một nguồn để lấy mẫu nữa và lần sau khi sử dụng, samplebạn sẽ phải tạo lại pooltừ một số nguồn. Việc triển khai của Derek chỉ xáo trộn hồ bơi, vì vậy nó có thể được tái sử dụng hoàn hảo để lấy mẫu mà không cần tạo lại. Và tôi tin rằng đây là trường hợp sử dụng thường xuyên nhất.
disfated

1

2020
phong cách lập trình chức năng không phá hủy, làm việc trong một bối cảnh bất biến.

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


Tôi nhận ra rằng hàm không tạo ra tất cả các mảng ngẫu nhiên có thể có từ một mảng nguồn. Trong thế giới khác, kết quả không phải là ngẫu nhiên như vậy ... bất kỳ ý tưởng cải thiện nào?
MAMY Sébastien

đâu là _shufflechức năng?
vanowm

0

Nó trích xuất từng phần tử ngẫu nhiên từ srcArray khi nó đã đủ hoặc không còn phần tử nào trong srcArray còn lại để giải nén. Nhanh chóng và đáng tin cậy.

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


Chào mừng đến với SO! Khi gửi bài trả lời, điều quan trọng là đề cập đến cách thức hoạt động mã của bạn và / hoặc làm thế nào nó giải quyết vấn đề OP của :)
Joel

0

2019

Điều này giống như câu trả lời của Laurynas Mališauskas , chỉ là các phần tử là duy nhất (không trùng lặp).

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

Bây giờ để trả lời câu hỏi ban đầu "Làm thế nào để lấy nhiều phần tử ngẫu nhiên bằng jQuery", bạn vào đây:

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

0

Đây là một hàm tôi sử dụng cho phép bạn dễ dàng lấy mẫu một mảng có hoặc không có thay thế:

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

Sử dụng nó rất đơn giản:

Không có thay thế (hành vi mặc định)

randomSample([1, 2, 3], 2) có thể trở lại [2, 1]

Với sự thay thế

randomSample([1, 2, 3, 4, 5, 6], 4) có thể trở lại [2, 3, 3, 2]


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

0

Tôi không thể tin rằng không ai không đề cập đến phương pháp này, khá rõ ràng và dễ hiểu.

const getRnd = (a, n) => new Array(n).fill(null).map(() => a[Math.floor(Math.random() * a.length)]);

Bạn không đảm bảo hai mục không bị lặp lại.
Valery

-2

Đây là câu trả lời đúng nhất và nó sẽ cung cấp cho bạn các yếu tố Ngẫu nhiên + Duy nhất.

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

Có điều gì đó kỳ lạ đang xảy ra với sự ngẫu nhiên trong cái này - tôi có kết quả tương tự hiển thị 6 trong số 9 lần thử (với n là 8 và kích thước mảng là 148). Bạn có thể nghĩ đến việc chuyển sang phương pháp Fisher-Yates ; đó là những gì tôi đã làm và bây giờ hoạt động tốt hơn nhiều.
asetniop

Điều này mất thời gian bậc hai vì nó thực hiện kiểm tra tính độc nhất không tốt và không có cơ hội như nhau để chọn mọi mục vì nó được sắp xếp bằng một so sánh ngẫu nhiên.
Ry-

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.