Obtendo um valor aleatório de uma matriz JavaScript


794

Considerar:

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

Como posso selecionar um valor aleatório dessa matriz usando JavaScript?

Respostas:


1482

É um one-liner simples

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

Exemplo

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


9
@SapphireSun isso está correto. Observe a Math.floor(Math.random(...))chamada, que arredonda para baixo.
precisa saber é o seguinte

33
Ahh, eu aprendi algo novo. Eu estava discutindo o caso em que ele é EXATAMENTE 1, mas aparentemente (de acordo com o W3Schools) Math.random está entre 0 inclusivo e 1 exclusivo. Foi mal.
SapphireSun

13
Eu posso estar errado, mas me lembro var rand = myArray[Math.random() * myArray.length>>0]de ser um pouco mais rápido
vrugtehagel

6
apenas no caso, se você já estiver usando lodash você pode usar _.sample (array)
Gabriel Matusevich

2
Prefiro esta variante:var rand = myArray[Math.random() * myArray.length | 0]
Nicolas

76

Se você já possui sublinhado ou lodash incluído no seu projeto, pode usar _.sample.

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

Se você precisar obter mais de um item aleatoriamente, poderá passar isso como um segundo argumento em sublinhado:

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

ou use o _.sampleSizemétodo no lodash:

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

Ao usar texto datilografado: Esteja ciente de que o tipo de retorno seria "string | indefinido" em vez de "string", devido a uma matriz de strings.
Stephan Schielke

23

Método de protótipo

Se você planeja obter muito um valor aleatório, pode definir uma função para ele.

Primeiro, coloque isso no seu código em algum lugar:

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

Agora:

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

Código liberado para o domínio público sob os termos da licença CC0 1.0 .


E isso faz o que?
Ken afiada

3
@KenSharp ele permite que você chamar .sample()em qualquer matriz para obter um item aleatório
Ben Aubin

5
A extensão de tipos de objetos nativos deve ser evitada. Eu apaguei minha resposta, pois ela foi muito votada, mas promovendo más práticas. Para obter mais discussões sobre esse assunto, consulte, por exemplo, stackoverflow.com/questions/14034180/… e eslint.org/docs/rules/no-extend-native
Markus Amalthea Magnuson

20

~~é muito mais rápido que Math.Floor(), portanto, quando se trata de otimização de desempenho enquanto produz saída usando elementos da interface do usuário, ~~vence o jogo. MAIS INFORMAÇÕES

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

Mas se você souber que a matriz terá milhões de elementos, poderá reconsiderar entre o Bitwise Operator e Math.Floor(), como o operador bit a bit se comporta estranhamente com grandes números. Veja o exemplo abaixo explicado com a saída. MAIS INFORMAÇÕES

var number = Math.floor(14444323231.2); // => 14444323231
var number = 14444323231.2 | 0; // => 1559421343

1
Fazer a ligação está morto, pós no entanto interessante e eu vou estar usando isso mais do que Math.flooragora :)
aabbccsmith

1
usando "bit a bit não" operador, enquanto mais rápido, que não é legível, então você tem que escolher o que é mais importante para você
Maciej Urbański

16

Digamos que você queira escolher um item aleatório diferente da última vez (não muito aleatório, mas ainda um requisito comum) ...

Com base na resposta de @Markus, podemos adicionar outra função de protótipo:

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 implemente da seguinte maneira:

var myRandomDiffElement = myArray.randomDiffElement(lastRandomElement)

11

Se você tiver valores fixos (como a lista de nomes do mês) e quiser uma solução de uma linha

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

A segunda parte da matriz é uma operação de acesso, conforme descrito em Por que [5,6,8,7] [1,2] = 8 em JavaScript?


2
Esse código é uma prática ruim e prejudicial. Nunca deve ser usado na produção. Possui baixa legibilidade e comprimento de matriz codificado. A pessoa que altera a entrada da matriz pode esquecer de editar o comprimento codificado no final.
Gaivota

O @Seagull OP nunca solicitou um ambiente específico. Além disso, este comentário não tem sentido, uma vez que poderia ser aplicada a quase todas as respostas a esta pergunta;)
IG Pascual

Mas a maioria das pessoas chega a essa pergunta na pesquisa do Google e pode usar a solução em outros cenários que não o OP original.
Gaivota

@ As pessoas da Seagull Haha são livres para decidir qual abordagem usar, eu não sou o faq de diretrizes de código limpo!
IG Pascual

10

A versão mais curta:

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

O que | 0faz?
Ken afiada

2
Ele transformará Float em Int, o mesmo que Math.floor.
foxiris

4
O @KenSharp em | 0si é uma operação bit a bit que não faz nada, mas no javascript os flutuadores são convertidos em ints antes de qualquer operação bit a bit . Portanto, é algo como + ''realmente não faz nada, mas pode ser usado para converter coisas em strings.
Dshepherd 19/09/19

Não é a mesma coisa, Math.floormas é a coisa correta a ser feita aqui. É um operador, por isso é mais rápido do Math.floorque apenas porque a qualquer momento durante a execução de algum código pode fazer Math.floor = someOtherFunctione eles não podem fazer o mesmo para '|'. Por outro lado, como para Math.floore |ser diferente tentativa Math.floor(-1.5)vs -1.5 | 0. A propósito, você não precisa dos parênteses. |tem uma precedência muito baixa.
gman

7

Se você deseja escrevê-lo em uma linha, como a solução de Pascual, outra solução seria escrevê-lo usando a função find do ES6 (com base no fato de que a probabilidade de selecionar aleatoriamente um dos nitens é 1/n):

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

Use essa abordagem para fins de teste e se houver um bom motivo para não salvar a matriz apenas em uma variável separada. Caso contrário, as outras respostas ( floor(random()*lengthe usando uma função separada) são o seu caminho.


Solução muito original. Bom trabalho! A propósito, a única solução real e dinâmica de uma linha aqui.
Slavik Meltser 19/03

7

O Faker.js possui muitas funções utilitárias para gerar dados de teste aleatórios. É uma boa opção no contexto de um conjunto de testes:

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

Como os comentaristas mencionaram, geralmente você não deve usar esta biblioteca no código de produção.


8
Para um problema simples como esse, a adição de uma dependência para uma biblioteca inteira é desnecessária e aumenta o inchaço do código. Se alguma coisa, você poderia recomendar o método real a partir do Fakerqual seleciona um elemento de matriz aleatória.
Pixxl

1
"Problemas simples" como esse geralmente são resolvidos por bibliotecas que fornecem uma solução simples para um problema que centenas de pessoas já tiveram que enfrentar. Essas bibliotecas geralmente são robustas e bem depuradas e lida com várias advertências que não queremos reimplementar. Normalmente, seria a situação em que eu recomendaria o uso de uma biblioteca.
Smonff 16/05/19

Do que você deve simplesmente copiar esse método uma da biblioteca e colocá-lo em um arquivo utils
Rick Bross

O conselho de que as bibliotecas devem ser avaliadas quanto ao peso / custo da página WRT quando são enviadas para um navegador da Web é um bom conselho e eu concordo plenamente que o envio do Faker.js para um navegador seria ridículo. No entanto, a pergunta não menciona qual tempo de execução JS está sendo usado. Para um tempo de execução baseado em NodeJS, dependências mais pesadas são perfeitamente razoáveis, e é o caso de onde estou usando o Faker.js - nos conjuntos de teste do Cucumber JS.
Nathan

6

A edição do protótipo da matriz pode ser prejudicial. Aqui está uma função simples de fazer o trabalho.

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

3

Função autônoma recursiva que pode retornar qualquer número de itens (idêntico ao 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])
}

2

Para obter uma matriz de formulários aleatórios de itens com criptografia forte, 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) )


1

Isso é semelhante, mas mais genérico, à solução de @Jacob Relkin:

Este é o ES2015:

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

O código funciona selecionando um número aleatório entre 0 e o comprimento da matriz, retornando o item nesse índice.


1

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

ou versão mais curta equivalente:

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

Código de amostra:

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


1

Função simples:

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

OU

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

OU

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

Seria melhor definir a variável myArrayy dentro da sua função para não poluir o espaço para nome global.
19418 Neil Meyer

0

Na minha opinião, melhor do que mexer com protótipos ou declará-lo bem a tempo, prefiro expô-lo à janela:

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

Agora em qualquer lugar do seu aplicativo, você chama assim:

var rand = window.choice.call(array)

Dessa forma, você ainda pode usar o for(x in array)loop corretamente


1
Eu não estava aqui quando alguém o votou positivamente, e não o fiz, mas meu palpite é que expô-lo à janela está basicamente declarando uma variável global. Veja: stackoverflow.com/questions/2613310/…
Chris

1
Você nunca deve usar for...inmatrizes ou mesmo em geral. Você corre o risco de percorrer a cadeia de protótipos. Também é destinado a todas as propriedades de um objeto, nem todos os índices em uma matriz. Se você deseja usar um iterador em uma matriz, use for (var i = 0; i < foo.length; i++){}. Melhor ainda, use algo como isso Array.prototype.forEach.
Robert

1
Eu não prefiro isso porque polui o escopo global. Você poderia dizer que esse pode ser o único a estar lá, mas dará hábitos de violar essas boas práticas.
21916 Jekk

0

Eu encontrei uma maneira de contornar as complicações da resposta principal, apenas concatenando a variável rand para outra variável que permite que esse número seja exibido dentro da chamada de myArray [] ;. Ao excluir a nova matriz criada e brincar com suas complicações, criei uma solução funcional:

<!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>

Estou confuso porque concatestá sempre mudando aqui ... randomem si não está mudando isso, e nada mais está sendo chamado mais de uma vez ....
BalinKingOfMoria Reintegrar CMs

1
Esta solução não faz totalmente sentido. Por que você está criando uma variável chamada concat?
superluminário 15/05

0

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

Você define uma variável constante para a matriz, em seguida, tem outra constante que escolhe aleatoriamente entre os três objetos na matriz e a função simplesmente retorna os resultados.


-1

Uma maneira genérica de obter elementos aleatórios:

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


-1

O randojs torna isso um pouco mais simples e legível:

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


1
Apenas curioso: por que os votos negativos?
Leponzo 20/02

1
algumas pessoas não gostam de procurar nas bibliotecas códigos que eles próprios poderiam escrever, mesmo que isso tornasse as coisas mais rápidas e mais legíveis. se a biblioteca ficar inativa por algum motivo, seu site agora tem uma falha. randojs não diminui, mas eles não sabem disso porque não são tão conhecidos como bibliotecas como o jQuery, por exemplo
Aaron Plocharczyk em 21/02

-2

Aqui está um exemplo de como fazê-lo:

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

-2

outro método fácil:

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

var randomValue = myArray[Math.round((Math.random()*1000))%myArray.length];

-3

Crie um valor aleatório e passe para a matriz

Por favor, tente o seguinte 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);

5
Esta resposta usa a mesma solução que a resposta já aceita. Você deve abster-se de adicionar a mesma solução duas vezes e, em vez disso, apresentar apenas outras alternativas possíveis que contribuiriam mais para a conversa.
Pixxl
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.