Jak uzyskać liczbę losowych elementów z tablicy?


107

Pracuję nad „jak uzyskać dostęp do elementów losowo z tablicy w javascript”. Znalazłem wiele linków na ten temat. Like: Pobierz losowy element z tablicy JavaScript

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

Ale w tym przypadku możemy wybrać tylko jedną pozycję z tablicy. Jeśli chcemy więcej niż jednego elementu, jak możemy to osiągnąć? Jak możemy uzyskać więcej niż jeden element z tablicy?


5
Po prostu wykonać to kilka razy?
Bergi

2
Czy na podstawie tego stwierdzenia możemy to zrobić? Pętla generująca duplikaty.
Shyam Dixit

1
Z tego dokładnego stwierdzenia nie można uzyskać więcej niż jednego elementu.
Sébastien

1
Ach, powinieneś powiedzieć, że nie chcesz duplikatów. Następnie sprawdź Unikalne liczby losowe w O (1)? a moja odpowiedź pod adresem Generuj unikalny numer w zakresie (0 - X), zachowując historię, aby zapobiec duplikatom
Bergi

1
Zrobiłem JsPerf, aby przetestować tutaj niektóre rozwiązania. @ Bergi wydaje się ogólnie najlepsze, podczas gdy moje działa lepiej, jeśli potrzebujesz wielu elementów z tablicy. jsperf.com/k-random-elements-from-array
Tibos

Odpowiedzi:


108

Wypróbuj tę nieniszczącą (i szybką ) funkcję:

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

13
Hej stary, chciałem tylko powiedzieć, że spędziłem około dziesięciu minut, doceniając piękno tego algorytmu.
Prajeeth Emanuel

Sugerowałbym użycie implementacji Pythona, jeśli zależy ci na szybkości: jsperf.com/pick-random-elements-from-an-array
Derek 朕 會 功夫

@Derek 朕 會 功夫 Ach, sprytne, to działa znacznie lepiej dla małych próbek z dużych zakresów. Zwłaszcza z użyciem ES6 Set(który nie był dostępny w '13: - /)
Bergi

@AlexWhite Dzięki za opinie, nie mogę uwierzyć, że ten błąd omijał wszystkich przez lata. Naprawiony. Powinieneś był jednak opublikować komentarz, a nie zasugerować zmiany.
Bergi,

2
@ cbdev420 Tak, to tylko (częściowe) tasowanie rybaków
Bergi

196

Tylko dwie linie:

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


23
Bardzo dobrze! Oczywiście możliwy jest również jeden liniowiec:let random = array.sort(() => .5 - Math.random()).slice(0,n)
unitario

1
Geniusz! Elegancki, krótki i prosty, szybki, wykorzystujący wbudowaną funkcjonalność.
Vlad,

37
To miłe, ale nie jest przypadkowe. Pierwszy przedmiot ma znacznie większe szanse na wybranie niż ostatni. Zobacz tutaj, dlaczego: stackoverflow.com/a/18650169/1325646
pomber

To nie zachowuje rodzaju oryginalnej tablicy
almathie

4
Niesamowity! jeśli chcesz zachować tablicę w stanie nienaruszonym, możesz po prostu zmienić pierwszą linię w następujący sposób: const shuffled = [... tablica] .sort (() => 0.5 - Math.random ());
Yair Levy


12

Portowanie .sampleze standardowej biblioteki Pythona:

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

Implementacja przeniesiona z Lib / random.py .

Uwagi:

  • setsizejest ustawiony na podstawie charakterystyk w Pythonie pod kątem wydajności. Chociaż nie został dostosowany do JavaScript, algorytm będzie nadal działał zgodnie z oczekiwaniami.
  • Niektóre inne odpowiedzi opisane na tej stronie nie są bezpieczne zgodnie ze specyfikacją ECMAScript z powodu niewłaściwego użycia Array.prototype.sort. Algorytm ten jednak gwarantuje zakończenie w określonym czasie.
  • W przypadku starszych przeglądarek, które nie mają Setzaimplementowanych, zestaw można zastąpić rozszerzeniem Arrayi .has(j)zastąpić .indexOf(j) > -1.

Wydajność w stosunku do zaakceptowanej odpowiedzi:


Poniżej zamieściłem zoptymalizowaną wersję tego kodu. Poprawiono również zły parametr losowy w drugim algo w twoim poście. Zastanawiam się, ile osób korzysta z poprzedniej tendencyjnej wersji w produkcji, mam nadzieję, że nie ma nic krytycznego.
użytkownik

11

Zdobycie 5 losowych przedmiotów bez zmiany oryginalnej tablicy:

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

(Nie używaj tego do dużych list)


Czy moglibyśmy lepiej wyjaśnić, jak to działa?
Qasim

10

stworzyć funkcję, która to robi:

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

powinieneś również sprawdzić, czy sourceArray ma wystarczającą liczbę elementów do zwrócenia. a jeśli chcesz, aby zwracane były unikalne elementy, powinieneś usunąć wybrany element z sourceArray.


Dobra odpowiedź! Spójrz na moją odpowiedź, skopiowałem Twój kod i dodałem funkcjonalność „tylko unikalne elementy”.
evilReiko,

1
Ta funkcja może zwrócić ten sam element sourceArraywiele razy.
Sampo

6

Składnia ES6

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

6

Jeśli chcesz losowo pobierać elementy z tablicy w pętli bez powtórzeń, możesz usunąć wybrany element z tablicy za pomocą 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
Dlaczego w zestawieniu items.splice (idx, 1) używasz „1”? splatać??
Shyam Dixit

2
Shyam Dixit , zgodnie z dokumentacją MDN1 jest deleteCountwskazanie liczby starych elementów tablicy usunąć. (Nawiasem mówiąc, zredukowałem ostatnie dwie linie do newItems.push(items.splice(idx, 1)[0])).
Kurt Peek

5

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

Pobiera jeden lub n losowych elementów w unikatowych kluczach z kolekcji do rozmiaru kolekcji.

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

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

Co to jest _? To nie jest standardowy obiekt JavaScript.
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();

2

Oto ładnie napisana wersja. Nie zawodzi. Zwraca przetasowaną tablicę, jeśli rozmiar próbki jest większy niż długość oryginalnej tablicy.

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

W tej odpowiedzi chcę podzielić się z wami testem, że muszę znać najlepszą metodę dającą równe szanse wszystkim elementom na losową podtablicę.

Metoda 01

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

przy użyciu tej metody niektóre elementy mają większe szanse w porównaniu z innymi.

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)

Metoda 2

Stosując tę ​​metodę, elementy mają takie samo prawdopodobieństwo:

 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)

Prawidłowa odpowiedź znajduje się w poniższym linku: https://stackoverflow.com/a/46545530/3811640


2

Nieniszczący
funkcjonalny styl programowania 2020 , działający w niezmiennym kontekście.

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


Zdaję sobie sprawę, że funkcja nie generuje wszystkich możliwych tablic losowych z tablicy źródłowej. Na innym świecie wynik nie jest tak przypadkowy, jak powinien ... jakikolwiek pomysł na poprawę?
MAMY Sébastien

gdzie jest _shufflefunkcja?
vanowm

Również, gdy size >= ar.lengthwynik będziesize-1
idleberg

1

EDYCJA : To rozwiązanie jest wolniejsze niż inne przedstawione tutaj (które łączą tablicę źródłową), jeśli chcesz uzyskać tylko kilka elementów. Szybkość tego rozwiązania zależy tylko od liczby elementów w pierwotnej tablicy, podczas gdy szybkość rozwiązania splicingu zależy od liczby elementów wymaganych w macierzy wyjściowej.

Jeśli chcesz nie powtarzających się losowych elementów, możesz przetasować swoją tablicę, a następnie uzyskać tylko tyle, ile chcesz:

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

Funkcja Shuffle pobrana stąd: https://stackoverflow.com/a/6274398/1669279


To zależy od procentu losowych elementów wymaganych z tablicy. Jeśli chcesz 9 losowych elementów z 10-elementowej tablicy, na pewno szybciej będzie tasować niż wyodrębnić 9 losowych elementów jeden po drugim. Jeśli procent, dla którego jest to przydatne, jest mniejszy niż 50%, istnieją przypadki użycia, w których to rozwiązanie jest najszybsze. W przeciwnym razie przyznam, że jest to bezużyteczne :).
Tibos

Chodziło mi o to, że tasowanie 9 elementów jest szybsze niż tasowanie 10 elementów. Przy okazji jestem przekonany, że OP nie chce zniszczyć swojej tablicy wejściowej…
Bergi,

Chyba nie rozumiem, jak tasowanie 9 elementów pomaga w tym problemie. Zdaję sobie sprawę, że jeśli chcesz mieć więcej niż połowę tablicy, możesz po prostu wyciąć losowe elementy, aż pozostaniesz z liczbą, którą chcesz, a następnie potasować, aby uzyskać losową kolejność. Czy jest coś, co przegapiłem? PS: Naprawiono zniszczenie tablicy, dzięki.
Tibos

Nie ma nic wspólnego z „połową”. Musisz tylko wykonać tyle pracy, ile elementów, które chcesz odzyskać, nie musisz w żadnym momencie traktować całej tablicy. Twój obecny kod ma złożoność O(n+k)(n elementów w tablicy, chcesz ich k), podczas gdy O(k)byłby możliwy (i optymalny).
Bergi

1
OK, twój kod ma więcej elementów podobnych do tych, O(2n)które można by zredukować O(n+k), gdybyś zmienił pętlę na while (counter-- > len-k)i usunął z niej ostatnie (zamiast pierwszych) kelementy. Rzeczywiście splice(i, 1)nie ma O(1), ale O(k)rozwiązanie jest nadal możliwe (zobacz moją odpowiedź). Jednak złożoność przestrzeni kosmicznej pozostaje O(n+k)niestety, ale może się stać w O(2k)zależności od implementacji rzadkiej tablicy.
Bergi

1

Potrzebowałem funkcji do rozwiązania tego rodzaju problemu, więc udostępniam ją tutaj.

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

Uwaga: jeśli n = arr.lengthto w zasadzie tasujesz tablicę arri randomItemszwracasz tę shuffled tablicę.

Próbny


1

Oto zoptymalizowana wersja kodu przeniesionego z Pythona przez @Derek, z dodaną opcją destrukcyjną (w miejscu), która sprawia, że ​​jest to najszybszy możliwy algorytm, jeśli możesz z nim skorzystać. W przeciwnym razie albo tworzy pełną kopię, albo w przypadku niewielkiej liczby elementów żądanych z dużej tablicy przełącza się na algorytm oparty na wyborze.

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

W porównaniu z implementacją Dereka, pierwszy algorytm jest znacznie szybszy w Firefoksie, a nieco wolniejszy w Chrome, chociaż teraz ma destrukcyjną opcję - najbardziej wydajną. Drugi algorytm jest po prostu szybszy o 5-15%. Staram się nie podawać żadnych konkretnych liczb, ponieważ różnią się one w zależności od k i ni prawdopodobnie nie będą miały żadnego znaczenia w przyszłości w nowych wersjach przeglądarek.

Heurystyka, która dokonuje wyboru między algorytmami, pochodzi z kodu Pythona. Zostawiłem go tak, jak jest, chociaż czasami wybiera wolniejszy. Powinien być zoptymalizowany pod kątem JS, ale jest to złożone zadanie, ponieważ wydajność przypadków narożnych zależy od przeglądarki i ich wersji. Na przykład, gdy spróbujesz wybrać 20 z 1000 lub 1050, przełączy się odpowiednio na pierwszy lub drugi algorytm. W tym przypadku pierwszy z nich działa 2x szybciej niż drugi w Chrome 80, ale 3x wolniej w Firefoksie 74.


Wystąpił błąd, log(k*3, 4)ponieważ JS nie ma baseargumentu. Należylog(k*3)/log(4)
disfated

Widzę również wadę w części, w której ponownie używasz pooljako pliku result. Ponieważ obcięto, poolnie można go już używać jako źródła do samplowania i następnym razem będziesz samplemusiał ponownie utworzyć poolz jakiegoś źródła. Implementacja Dereka tylko tasuje pulę, więc można ją idealnie ponownie wykorzystać do pobierania próbek bez odtwarzania. Uważam, że jest to najczęstszy przypadek użycia.
disfated

@ niezadowolony, dzięki, naprawiony logw kodzie moim i Dereka. Jeśli chodzi o ponowne użycie pool, po prostu nie włączaj tej destructiveopcji, a poolargument zostanie przesłany w cień z kopią.
użytkownik

0

Wyodrębnia losowe elementy z srcArray jeden po drugim, póki wystarcza lub nie ma już elementów w srcArray do wyodrębnienia. Szybki i niezawodny.

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


Witamy w SO! Pisząc odpowiedzi, ważne jest, aby wspomnieć, jak działa twój kod i / lub jak rozwiązuje problem OP :)
Joel

0

2019

To jest to samo, co odpowiedź Laurynasa Mališauskasa , tyle że elementy są unikalne (bez duplikatów).

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

A teraz, aby odpowiedzieć na oryginalne pytanie „Jak uzyskać wiele losowych elementów przez jQuery”, proszę bardzo:

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

Oto funkcja, której używam, która umożliwia łatwe próbkowanie tablicy z wymianą lub bez:

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

Korzystanie z niego jest proste:

Bez zamiany (zachowanie domyślne)

randomSample([1, 2, 3], 2) może wrócić [2, 1]

Z wymianą

randomSample([1, 2, 3, 4, 5, 6], 4) może wrócić [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

Nie mogę uwierzyć, że nikt nie wspomniał o tej metodzie, całkiem przejrzystej i prostej.

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

Nie upewniasz się, że dwa elementy się nie powtórzą.
Valery

-2

Oto najbardziej poprawna odpowiedź, która da ci elementy losowe + unikalne.

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

Z randomizacją w tym przypadku dzieje się coś dziwnego - miałem ten sam wynik, który pokazał 6 z 9 prób (z n równą 8 i rozmiarem tablicy 148). Możesz pomyśleć o przejściu na metodę Fishera-Yatesa ; to właśnie zrobiłem i teraz działa znacznie lepiej.
asetniop

Zajmuje to czas kwadratowy, ponieważ wykonuje złą kontrolę niepowtarzalności i nie ma równych szans na wybranie każdego elementu, ponieważ sortuje się z przypadkowym porównaniem.
Ry-

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.