web-dev-qa-db-fra.com

Comment obtenir n aucun élément au hasard dans un tableau

Je travaille sur 'comment accéder aux éléments au hasard à partir d'un tableau en javascript'. J'ai trouvé de nombreux liens à ce sujet. Like: Obtenir un élément aléatoire du tableau JavaScript

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

Question: Mais dans ce cas, nous ne pouvons choisir qu’un élément du tableau. .

44
Shyam Dixit

Essayez cette fonction non destructive (et rapide ):

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

Juste deux lignes: 

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

DÉMO :

67
Abdennour TOUMI

créer une fonction qui fait ça:

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

vous devriez également vérifier si le sourceArray a suffisamment d'éléments à renvoyer. et si vous souhaitez que des éléments uniques soient renvoyés, vous devez supprimer l’élément sélectionné du tableau source.

10

Obtenir 5 éléments aléatoires sans changer le tableau d'origine:

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

(N'utilisez pas ceci pour les grandes listes)

7
pomber

Porter .sample à partir de la bibliothèque standard 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;
}

L'implémentation a porté de Lib/random.py .

Remarques: 

  • setsize est défini en fonction des caractéristiques de Python pour plus d’efficacité. Bien qu'il n'ait pas été ajusté pour JavaScript, l'algorithme fonctionnera toujours comme prévu.
  • Certaines autres réponses décrites dans cette page ne sont pas sécuritaires selon la spécification ECMAScript en raison de l’utilisation abusive de Array.prototype.sort. Cet algorithme est cependant garanti pour se terminer en temps fini.
  • Pour les navigateurs plus anciens pour lesquels Set n'est pas implémenté, l'ensemble peut être remplacé par un Array et .has(j) remplacé par .indexOf(j) > -1.

Performance par rapport à la réponse acceptée:

5
Derek 朕會功夫

Syntaxe ES6

const pickRandom = (arr,count) => {
  let _arr = [...arr];
  return[...Array(count)].map( ()=> _arr.splice(Math.floor(Math.random() * _arr.length), 1)[0] ); 
}
3
Yair Levy
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
Archy Wilhes

Si vous souhaitez extraire aléatoirement des éléments du tableau dans une boucle sans répétition, vous devez supprimer l'élément sélectionné du tableau avec 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);
}

Exemple de violon

2
Rory McCrossan

J'avais besoin d'une fonction pour résoudre ce genre de problème, alors je la partage ici.

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

Remarque: si n = arr.length, vous mélangez le tableau arr et randomItems renvoie ce tableau mélangé. 

Démo

1
Storage Lenovo

Voici une version bien typée. Ça n'échoue pas. Retourne un tableau mélangé si la taille de l'échantillon est supérieure à la longueur du tableau d'origine.

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

EDIT: cette solution est plus lente que les autres présentées ici (qui joignent le tableau source) si vous souhaitez obtenir uniquement quelques éléments. La vitesse de cette solution dépend uniquement du nombre d'éléments dans la matrice d'origine, tandis que la vitesse de la solution de raccordement dépend du nombre d'éléments requis dans la matrice en sortie.

Si vous voulez des éléments aléatoires non répétitifs, vous pouvez mélanger votre tableau et n'en obtenir que le nombre souhaité:

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

Fonction de lecture aléatoire prise à partir d'ici: https://stackoverflow.com/a/6274398/1669279

1
Tibos

Il extrait les éléments aléatoires de srcArray un par un pendant qu'il en a assez ou qu'il ne reste plus d'éléments dans srcArray pour l'extraction . Rapide et fiable.

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

0
Aleksey Yaremenko

2019

C'est la même chose que Laurynas Mališauskas répondez, mais les éléments sont uniques (pas de doublons).

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

Maintenant, pour répondre à la question initiale "Comment obtenir plusieurs éléments aléatoires par jQuery", voici ce qui se passe:

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
evilReiko

Voici une fonction que j’utilise qui vous permet d’échantillonner facilement un tableau avec ou sans remplacement:

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

Son utilisation est simple:

sans remplacement (comportement par défaut)

randomSample([1, 2, 3], 2) peut renvoyer [2, 1]

avec remplacement

randomSample([1, 2, 3, 4, 5, 6], 4) peut renvoyer [2, 3, 3, 2]

0
Jared Wilber