Obtener un valor aleatorio de una matriz de JavaScript

794

Considerar:

var myArray = ['January', 'February', 'March'];    

¿Cómo puedo seleccionar un valor aleatorio de esta matriz usando JavaScript?

Sarah
fuente

Respuestas:

1482

Es una línea simple

const randomElement = array[Math.floor(Math.random() * array.length)];

Ejemplo

const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
const randomMonth = months[Math.floor(Math.random() * months.length)];

console.log("random month =>", randomMonth);

Jacob Relkin
fuente
99
@SapphireSun esto es correcto. Tenga en cuenta la Math.floor(Math.random(...))llamada, que se redondea hacia abajo.
cenizas999
33
Ahh, he aprendido algo nuevo. Estaba discutiendo el caso en el que es EXACTAMENTE 1, pero aparentemente (según W3Schools) Math.random está entre 0 inclusivo y 1 exclusivo. Culpa mía.
SapphireSun
13
Podría estar equivocado, pero recuerdo var rand = myArray[Math.random() * myArray.length>>0]haber sido un poco más rápido
vrugtehagel
66
por si acaso, si ya está usando lodash, puede usar _.sample (array)
Gabriel Matusevich
2
Prefiero esta variante:var rand = myArray[Math.random() * myArray.length | 0]
Nicolas
76

Si ya tiene subrayado o lodash incluido en su proyecto, puede usarlo _.sample.

// will return one item randomly from the array
_.sample(['January', 'February', 'March']);

Si necesita obtener más de un elemento al azar, puede pasarlo como segundo argumento en guión bajo:

// will return two items randomly from the array using underscore
_.sample(['January', 'February', 'March'], 2);

o use el _.sampleSizemétodo en lodash:

// will return two items randomly from the array using lodash
_.sampleSize(['January', 'February', 'March'], 2);
Brendan Nee
fuente
Cuando utilice el mecanografiado: Tenga en cuenta que el tipo de retorno sería "string | undefined" en lugar de "string" dada una matriz de string.
Stephan Schielke
23

Método de prototipo

Si planea obtener un valor aleatorio mucho, es posible que desee definir una función para él.

Primero, pon esto en tu código en alguna parte:

Array.prototype.sample = function(){
  return this[Math.floor(Math.random()*this.length)];
}

Ahora:

[1,2,3,4].sample() //=> a random element

Código publicado en el dominio público bajo los términos de la licencia CC0 1.0 .

Ben Aubin
fuente
¿Y esto hace qué?
Ken Sharp el
3
@KenSharp le permite llamar .sample()a cualquier matriz para obtener un elemento aleatorio
Ben Aubin
66
Se debe evitar extender los tipos de objetos nativos. He eliminado mi respuesta, al ver que se votó mucho, pero promoviendo las malas prácticas. Para obtener más información sobre este tema, consulte, por ejemplo, stackoverflow.com/questions/14034180/… y eslint.org/docs/rules/no-extend-native
Markus Amalthea Magnuson el
20

~~es mucho más rápido que Math.Floor(), por lo que cuando se trata de la optimización del rendimiento al producir resultados utilizando elementos de la interfaz de usuario, ~~gana el juego. MÁS INFORMACIÓN

var rand = myArray[~~(Math.random() * myArray.length)];

Pero si sabe que la matriz tendrá millones de elementos, es posible que desee reconsiderar entre el Operador a nivel de bits y Math.Floor(), dado que el operador a nivel de bits se comporta de manera extraña con números grandes. Vea el siguiente ejemplo explicado con la salida. MÁS INFORMACIÓN

var number = Math.floor(14444323231.2); // => 14444323231
var number = 14444323231.2 | 0; // => 1559421343
Ankur Soni
fuente
1
El enlace está muerto, sin embargo, la publicación es interesante y lo Math.floor
usaré
1
el uso del operador "bitwise not", aunque más rápido, no es tan fácil de leer, por lo que debe elegir qué es más importante para usted
Maciej Urbański
16

Digamos que desea elegir un elemento aleatorio que sea diferente de la última vez (no realmente aleatorio, pero sigue siendo un requisito común) ...

Sobre la base de la respuesta de @Markus, podemos agregar otra función prototipo:

Array.prototype.randomDiffElement = function(last) {
   if (this.length == 0) {
      return;
   } else if (this.length == 1) {
      return this[0];
   } else {
      var num = 0;
      do {
         num = Math.floor(Math.random() * this.length);
      } while (this[num] == last);
      return this[num];
   }
}

E implementar así:

var myRandomDiffElement = myArray.randomDiffElement(lastRandomElement)
CrazyTim
fuente
11

Si tiene valores fijos (como una lista de nombres de mes) y desea una solución de una línea

var result = ['January', 'February', 'March'][Math.floor(Math.random() * 3)]

La segunda parte de la matriz es una operación de acceso como se describe en ¿Por qué [5,6,8,7] [1,2] = 8 en JavaScript?

IG Pascual
fuente
2
Tal código es una práctica mala y dañina. Nunca debe usarse en producción. Tiene baja legibilidad y tiene una longitud de matriz codificada. La persona que cambia la entrada de la matriz puede olvidarse de editar la longitud codificada al final.
Gaviota
@Seagull OP nunca solicitó un entorno específico. Además, este comentario no tiene sentido, ya que podría aplicarse a casi todas las respuestas en esta pregunta;)
IG Pascual
Pero la mayoría de las personas llegan a esta pregunta desde la búsqueda de Google y pueden usar la solución en otros escenarios que no sean el OP original.
Gaviota
@Seagull Jaja, las personas son libres de decidir qué enfoque usar, ¡no soy el faq de guía de código limpio!
IG Pascual
10

La versión más corta:

var myArray = ['January', 'February', 'March']; 
var rand = myArray[(Math.random() * myArray.length) | 0]
Foxiris
fuente
¿Qué | 0hacer?
Ken Sharp el
2
Girará Float a Int, igual que Math.floor.
foxiris el
44
@KenSharp en | 0sí es una operación bit a bit que no hace nada, pero en javascript los flotadores se convierten en ints antes de cualquier operación bit a bit . Entonces, es algo así como + ''que realmente no hace nada, pero se puede usar para convertir cosas en cadenas.
dshepherd
No es lo mismo Math.floorpero es lo correcto hacer aquí. Es un operador, por lo que es más rápido que Math.floorsi solo porque en cualquier momento mientras se ejecuta un código puede hacer Math.floor = someOtherFunctiony no pueden hacer lo mismo para '|'. Por otro lado como para Math.floory |ser diferente intento Math.floor(-1.5)vs -1.5 | 0. Por cierto, no necesitas los paréntesis. |Tiene una muy baja precedencia.
gman
7

Si desea escribirlo en una línea, como la solución de Pascual, otra solución sería escribirlo utilizando la función de búsqueda de ES6 (basado en el hecho de que la probabilidad de seleccionar uno de los nelementos al azar es 1/n):

var item = ['A', 'B', 'C', 'D'].find((_, i, ar) => Math.random() < 1 / (ar.length - i));
console.log(item);

Use ese enfoque para fines de prueba y si hay una buena razón para no guardar la matriz solo en una variable separada. De lo contrario, las otras respuestas ( floor(random()*lengthy el uso de una función separada) son su camino a seguir.

Stephan
fuente
Solución muy original. ¡Gran trabajo! Por cierto, la única solución real y dinámica de una sola línea aquí.
Slavik Meltser
7

Faker.js tiene muchas funciones de utilidad para generar datos de prueba aleatorios. Es una buena opción en el contexto de un conjunto de pruebas:

const Faker = require('faker');
Faker.random.arrayElement(['January', 'February', 'March']);

Como los comentaristas han mencionado, generalmente no debe usar esta biblioteca en el código de producción.

Nathan
fuente
8
Para un problema simple como este, agregar una dependencia para una biblioteca completa es innecesario y se agrega a la hinchazón de código. En todo caso, podría recomendar el método real desde el Fakerque selecciona un elemento de matriz aleatorio.
Pixxl
1
Los "problemas simples" como este generalmente se resuelven mediante bibliotecas que brindan una solución simple a un problema que cientos de personas ya tuvieron que enfrentar. Esas bibliotecas suelen ser robustas y bien depuradas y se ocupan de varias advertencias que no queremos volver a implementar. Normalmente sería la situación en la que recomendaría usar una biblioteca.
smonff
De lo que debería copiar ese método de la biblioteca y ponerlo en un archivo de utilidades
Rick Bross,
El consejo de que las bibliotecas deben evaluarse por el costo / beneficio del peso de la página WRT cuando se envían a un navegador web es un buen consejo y estoy totalmente de acuerdo en que enviar Faker.js a un navegador sería ridículo. Sin embargo, la pregunta no menciona qué tiempo de ejecución de JS se está utilizando. Para un tiempo de ejecución basado en NodeJS, las dependencias más pesadas son perfectamente razonables, que es el caso para el que estoy usando Faker.js, en las suites de prueba Cucumber JS.
Nathan
6

La edición del prototipo de matriz puede ser perjudicial. Aquí es una función simple para hacer el trabajo.

function getArrayRandomElement (arr) {
  if (arr && arr.length) {
    return arr[Math.floor(Math.random() * arr.length)];
  }
  // The undefined will be returned if the empty array was passed
}

Uso:

// Example 1
var item = getArrayRandomElement(['January', 'February', 'March']);

// Example 2
var myArray = ['January', 'February', 'March'];
var item = getArrayRandomElement(myArray);
Gaviota
fuente
3

Función recursiva independiente que puede devolver cualquier número de elementos (idéntico a lodash.sampleSize ):

function getRandomElementsFromArray(array, numberOfRandomElementsToExtract = 1) {
    const elements = [];

    function getRandomElement(arr) {
        if (elements.length < numberOfRandomElementsToExtract) {
            const index = Math.floor(Math.random() * arr.length)
            const element = arr.splice(index, 1)[0];

            elements.push(element)

            return getRandomElement(arr)
        } else {
            return elements
        }
    }

    return getRandomElement([...array])
}
disminuido
fuente
2

Para obtener una matriz de forma de elemento aleatorio cripto-fuerte, use

let rndItem = a=> a[rnd()*a.length|0];
let rnd = ()=> crypto.getRandomValues(new Uint32Array(1))[0]/2**32;

var myArray = ['January', 'February', 'March'];

console.log( rndItem(myArray) )

Kamil Kiełczewski
fuente
1

Esto es similar pero más general que la solución de @Jacob Relkin:

Esto es ES2015:

const randomChoice = arr => {
    const randIndex = Math.floor(Math.random() * arr.length);
    return arr[randIndex];
};

El código funciona seleccionando un número aleatorio entre 0 y la longitud de la matriz, y luego devuelve el elemento en ese índice.

Max Heiber
fuente
1

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

o versión equivalente más corta:

var item = myArray[(Math.random()*myArray.length)|0];

Código de muestra:

var myArray = ['January', 'February', 'March'];    
var item = myArray[(Math.random()*myArray.length)|0];
console.log('item:', item);

Pavel P
fuente
1

Función simple:

var myArray = ['January', 'February', 'March'];
function random(array) {
     return array[Math.floor(Math.random() * array.length)]
}
random(myArray);

O

var myArray = ['January', 'February', 'March'];
function random() {
     return myArray[Math.floor(Math.random() * myArray.length)]
}
random();

O

var myArray = ['January', 'February', 'March'];
function random() {
     return myArray[Math.floor(Math.random() * myArray.length)]
}
random();
Dhakshith
fuente
Sería mejor establecer la variable myArrayy dentro de su función para no contaminar el espacio de nombres global.
Neil Meyer
0

En mi opinión, mejor que jugar con los prototipos o declararlo justo a tiempo, prefiero exponerlo a la ventana:

window.choice = function() {
  if (!this.length || this.length == 0) return;
  if (this.length == 1) return this[0];
  return this[Math.floor(Math.random()*this.length)];
}

Ahora, en cualquier lugar de su aplicación, lo llama así:

var rand = window.choice.call(array)

De esta manera, aún puede usar el for(x in array)bucle correctamente

frankies
fuente
1
No estaba aquí cuando alguien lo rechazó, y no lo rechacé, pero supongo que exponerlo a la ventana básicamente declara una variable global. Ver: stackoverflow.com/questions/2613310/…
Chris
1
Nunca debe usarlo for...inen matrices, o incluso en general. Corres el riesgo de caminar por la cadena del prototipo. También está destinado a todas las propiedades de un objeto, no a todos los índices de una matriz. Si desea usar un iterador en una matriz, use for (var i = 0; i < foo.length; i++){}. Aún mejor, use algo como en su Array.prototype.forEachlugar.
Robert
1
No prefiero esto porque contamina el alcance global. Se podría decir que este podría ser el único que esté allí, pero le dará la costumbre de violar esa buena práctica.
Jekk
0

He encontrado una forma de evitar las complicaciones de la respuesta principal, simplemente concatenando la variable rand con otra variable que permite que ese número se muestre dentro de la llamada de myArray [] ;. Al eliminar la nueva matriz creada y jugar con sus complicaciones, he encontrado una solución que funciona:

<!DOCTYPE html>
<html>
<body>

<p id="demo"></p>

<script>

var myArray = ['January', 'February', 'March', 'April', 'May'];    

var rand = Math.floor(Math.random() * myArray.length);

var concat = myArray[rand];

function random() {
   document.getElementById("demo").innerHTML = (concat);
}
</script>

<button onClick="random();">
Working Random Array generator
</button>

</body>
</html>
FaverosGema
fuente
Estoy confundido por qué concatsiempre está cambiando aquí ... randomsí no lo está cambiando, y nada más está siendo llamado más de una vez ....
BalinKingOfMoria Restablecer los CM
1
Esta solución no tiene todo el sentido. ¿Por qué estás creando una variable llamada concat?
superluminary
0

static generateMonth() { 
const theDate = ['January', 'February', 'March']; 
const randomNumber = Math.floor(Math.random()*3);
return theDate[randomNumber];
};

Establece una variable constante en la matriz, luego tiene otra constante que elige aleatoriamente entre los tres objetos en la matriz y luego la función simplemente devuelve los resultados.

Neil Meyer
fuente
-1

Una forma genérica de obtener elementos aleatorios:

let some_array = ['Jan', 'Feb', 'Mar', 'Apr', 'May'];
let months = random_elems(some_array, 3);

console.log(months);

function random_elems(arr, count) {
  let len = arr.length;
  let lookup = {};
  let tmp = [];

  if (count > len)
    count = len;

  for (let i = 0; i < count; i++) {
    let index;
    do {
      index = ~~(Math.random() * len);
    } while (index in lookup);
    lookup[index] = null;
    tmp.push(arr[index]);
  }

  return tmp;
}

Rafael
fuente
-1

randojs hace esto un poco más simple y legible:

console.log( rando(['January', 'February', 'March']).value );
<script src="https://randojs.com/1.0.0.js"></script>

Aaron Plocharczyk
fuente
1
Solo curiosidad: ¿por qué los votos negativos?
Leponzo
1
Algunas personas no son fanáticas de buscar en las bibliotecas el código que podrían escribir ellos mismos, incluso si esto hace que las cosas sean más rápidas y más legibles. Si la biblioteca deja de funcionar por algún motivo, su sitio web ahora tiene un problema técnico. randojs no baja, pero no lo saben porque no es tan conocido como las bibliotecas como jQuery, por ejemplo
Aaron Plocharczyk,
-2

Aquí hay un ejemplo de cómo hacerlo:

$scope.ctx.skills = data.result.skills;
    $scope.praiseTextArray = [
    "Hooray",
    "You\'re ready to move to a new skill", 
    "Yahoo! You completed a problem", 
    "You\'re doing great",  
    "You succeeded", 
    "That was a brave effort trying new problems", 
    "Your brain was working hard",
    "All your hard work is paying off",
    "Very nice job!, Let\'s see what you can do next",
    "Well done",
    "That was excellent work",
    "Awesome job",
    "You must feel good about doing such a great job",
    "Right on",
    "Great thinking",
    "Wonderful work",
    "You were right on top of that one",
    "Beautiful job",
    "Way to go",
    "Sensational effort"
  ];

  $scope.praiseTextWord = $scope.praiseTextArray[Math.floor(Math.random()*$scope.praiseTextArray.length)];
varun
fuente
-2

Otro método fácil:

var myArray = ['keke','keko','cano','halo','zirto'];

var randomValue = myArray[Math.round((Math.random()*1000))%myArray.length];
Kamuran Sönecek
fuente
-3

Crea un valor aleatorio y pasa a la matriz

Intenta seguir el siguiente código ...

//For Search textbox random value
var myPlaceHolderArray = ['Hotels in New York...', 'Hotels in San Francisco...', 'Hotels Near Disney World...', 'Hotels in Atlanta...'];
var rand = Math.floor(Math.random() * myPlaceHolderArray.length);
var Placeholdervalue = myPlaceHolderArray[rand];

alert(Placeholdervalue);
Jignesh Darji
fuente
55
Esta respuesta usa la misma solución que la respuesta ya aceptada. Debes abstenerte de agregar la misma solución dos veces y, en su lugar, solo debes mencionar otras posibles alternativas que contribuirían más a la conversación.
Pixxl