Uzyskiwanie losowej wartości z tablicy JavaScript

792

Rozważać:

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

Jak mogę wybrać losową wartość z tej tablicy za pomocą JavaScript?

Sarah
źródło

Odpowiedzi:

1479

Jest to prosty jednowarstwowy

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

Przykład

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
źródło
9
@SapphireSun to jest poprawne. Zanotuj Math.floor(Math.random(...))połączenie, które zaokrągla w dół.
ashes999
33
Ahh, nauczyłem się czegoś nowego. Omawiałem przypadek, w którym jest on DOKŁADNIE 1, ale najwyraźniej (według W3Schools) Math.random jest między 0 włącznie a 1 wyłącznym. Mój błąd.
SapphireSun
13
Mogę się mylić, ale przypominam sobie, że jestem var rand = myArray[Math.random() * myArray.length>>0]nieco szybszy
vrugtehagel
6
na wszelki wypadek, jeśli już używasz lodash, możesz użyć _.sample (tablica)
Gabriel Matusevich
2
Wolę ten wariant:var rand = myArray[Math.random() * myArray.length | 0]
Nicolas
76

Jeśli masz już podkreślenie lub lodash w swoim projekcie, możesz użyć _.sample.

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

Jeśli potrzebujesz losowo uzyskać więcej niż jeden przedmiot, możesz przekazać to jako drugi argument w podkreśleniu:

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

lub użyj _.sampleSizemetody w lodash:

// will return two items randomly from the array using lodash
_.sampleSize(['January', 'February', 'March'], 2);
Brendan Nee
źródło
Korzystając z maszynopisu: pamiętaj, że typem zwracanym jest „ciąg | niezdefiniowany” zamiast „ciąg” z uwzględnieniem tablicy ciągów.
Stephan Schielke
23

Metoda prototypowa

Jeśli planujesz często uzyskiwać losową wartość, możesz chcieć zdefiniować dla niej funkcję.

Najpierw umieść to gdzieś w kodzie:

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

Teraz:

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

Kod wydany do domeny publicznej zgodnie z warunkami licencji CC0 1.0 .

Ben Aubin
źródło
I co to robi?
Ken Sharp
3
@KenSharp pozwala na wywołanie .sample()dowolnej tablicy w celu otrzymania losowego przedmiotu
Ben Aubin
5
Należy unikać rozszerzania rodzimych typów obiektów. Usunąłem swoją odpowiedź, widząc, że została ona wysoko oceniona, ale promując złe praktyki. Aby uzyskać więcej dyskusji na ten temat patrz np stackoverflow.com/questions/14034180/... i eslint.org/docs/rules/no-extend-native
Markus Amalthea Magnuson
20

~~jest znacznie szybszy niż Math.Floor(), więc jeśli chodzi o optymalizację wydajności podczas tworzenia danych wyjściowych przy użyciu elementów interfejsu użytkownika, ~~wygrywa. WIĘCEJ INFORMACJI

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

Ale jeśli wiesz, że tablica będzie zawierać miliony elementów, możesz ponownie rozważyć między operatorem Math.Floor()bitowym i , ponieważ operator bitowy zachowuje się dziwnie z dużymi liczbami. Zobacz poniższy przykład objaśniony z danymi wyjściowymi. WIĘCEJ INFORMACJI

var number = Math.floor(14444323231.2); // => 14444323231
var number = 14444323231.2 | 0; // => 1559421343
Ankur Soni
źródło
1
Link jest martwy, jakkolwiek interesujący post i będę go używał częściej niż Math.floorteraz :)
aabbccsmith
użycie operatora „nie bitowego”, choć szybsze, nie jest aż tak czytelne, więc musisz wybrać to, co jest dla Ciebie ważniejsze
Maciej Urbański
16

Powiedzmy, że chcesz wybrać losowy przedmiot, który różni się od ostatniego razu (niezbyt losowy, ale wciąż powszechny wymóg) ...

Opierając się na odpowiedzi @Markus, możemy dodać kolejną funkcję prototypową:

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

I zaimplementuj tak:

var myRandomDiffElement = myArray.randomDiffElement(lastRandomElement)
CrazyTim
źródło
11

Jeśli masz ustalone wartości (np. Listę nazw miesięcy) i potrzebujesz rozwiązania jednowierszowego

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

Druga część tablicy to operacja dostępu opisana w Dlaczego w [5,6,8,7] [1,2] = 8 w JavaScript?

IG Pascual
źródło
2
Taki kod jest złą i szkodliwą praktyką. Nigdy nie należy go stosować w produkcji. Ma małą czytelność i sztywną długość tablicy. Osoba zmieniająca dane wejściowe tablicy może zapomnieć o edycji na stałe zakodowanej na końcu.
Mewa
@Seagull OP nigdy nie poprosił o określone środowisko. Również ten komentarz jest bez znaczenia, ponieważ można go zastosować do prawie wszystkich odpowiedzi w tym pytaniu;)
IG Pascual
Ale większość osób przychodzi do tego pytania z wyszukiwarki Google i może użyć rozwiązania w innych scenariuszach niż oryginalny OP.
Mewa
@Seagull Ludzie Haha mogą swobodnie decydować, które podejście zastosować, nie jestem często zadawanym pytaniem dotyczącym czystego kodu!
IG Pascual,
10

Najkrótsza wersja:

var myArray = ['January', 'February', 'March']; 
var rand = myArray[(Math.random() * myArray.length) | 0]
Foxiris
źródło
Co ma | 0zrobić?
Ken Sharp
2
Zamieni Float w Int, tak samo jak Math.floor.
foxiris
4
@KenSharp | 0sam w sobie jest bitową operacją, która nic nie robi, ale w javascript floaty są konwertowane na ints przed każdą operacją bitową . To coś w rodzaju tego, + ''że tak naprawdę nic nie robi, ale może być użyte do konwersji rzeczy na ciągi.
dshepherd,
To nie to samo, co tutaj, Math.floorale jest to właściwe. Jest to operator, więc jest szybszy niż Math.floorchoćby dlatego, że w dowolnym momencie podczas działania może zrobić jakiś kod Math.floor = someOtherFunctioni nie może zrobić tego samego dla „|”. Z drugiej strony, jak dla Math.floori |inności try Math.floor(-1.5)vs -1.5 | 0. Nawiasem mówiąc, nie potrzebujesz nawiasów. |ma bardzo niski priorytet.
gman
7

Jeśli chcesz napisać go w jednym wierszu, tak jak rozwiązanie Pascuala, innym rozwiązaniem byłoby napisanie go za pomocą funkcji wyszukiwania ES6 (w oparciu o fakt, że prawdopodobieństwo losowego wybrania jednego z nelementów wynosi 1/n):

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

Zastosuj to podejście do celów testowych i jeśli istnieje uzasadniony powód, aby nie zapisywać tablicy tylko w osobnej zmiennej. W przeciwnym razie pozostałe odpowiedzi ( floor(random()*lengthi korzystanie z oddzielnej funkcji) są na dobrej drodze.

Stephan
źródło
Bardzo oryginalne rozwiązanie. Dobra robota! Nawiasem mówiąc, jedyne prawdziwe i dynamiczne rozwiązanie z jedną linią.
Slavik Meltser
7

Faker.js ma wiele funkcji narzędziowych do generowania losowych danych testowych. Jest to dobra opcja w kontekście zestawu testów:

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

Jak wspomnieli komentatorzy, ogólnie nie powinieneś używać tej biblioteki w kodzie produkcyjnym.

Nathan
źródło
8
W przypadku takiego prostego problemu dodanie zależności dla całej biblioteki jest niepotrzebne i powoduje powiększenie kodu. Jeśli już, możesz potencjalnie polecić rzeczywistą metodę, z Fakerktórej wybiera się losowy element tablicy.
Pixxl
1
„Prosty problem”, taki jak ten, jest zwykle rozwiązywany przez biblioteki, które zapewniają proste rozwiązanie problemu, z którym setki osób już musiały się zmierzyć. Te biblioteki są zwykle solidne i dobrze debugowane i zajmują się różnymi zastrzeżeniami, których nie chcemy ponownie wdrażać. Zwykle byłaby to sytuacja, w której poleciłbym użyć biblioteki.
smonff
Następnie powinieneś po prostu skopiować tę metodę z biblioteki i umieścić ją w pliku utils
Rick Bross
Rada, że ​​biblioteki powinny być oceniane pod kątem wagi / korzyści strony WRT, gdy są wysyłane do przeglądarki internetowej, jest solidną radą i całym sercem zgadzam się, że wysyłanie Faker.js do przeglądarki byłoby absurdalne. Jednak pytanie nie wspomina, które środowisko wykonawcze JS jest używane. W przypadku środowiska wykonawczego opartego na NodeJS cięższe zależności są całkowicie uzasadnione, co ma miejsce w przypadku, gdy używam Faker.js - w zestawach testowych Cucumber JS.
Nathan
6

Edycja prototypu tablicy może być szkodliwa. Tutaj jest to prosta funkcja do wykonania pracy.

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
}

Stosowanie:

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

// Example 2
var myArray = ['January', 'February', 'March'];
var item = getArrayRandomElement(myArray);
Mewa
źródło
3

Rekurencyjna, samodzielna funkcja, która może zwrócić dowolną liczbę elementów (identyczne jak 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])
}
maleć
źródło
2

Aby uzyskać silną kryptowalutę losową formę formularza, użyj tablicy

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
źródło
1

Jest to podobne, ale bardziej ogólne niż rozwiązanie @Jacob Relkin:

To jest ES2015:

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

Kod działa, wybierając losową liczbę z zakresu od 0 do długości tablicy, a następnie zwracając element pod tym indeksem.

Max Heiber
źródło
1

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

lub równoważna krótsza wersja:

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

Przykładowy kod:

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

Pavel P.
źródło
1

Prosta funkcja:

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

LUB

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

LUB

var myArray = ['January', 'February', 'March'];
function random() {
     return myArray[Math.floor(Math.random() * myArray.length)]
}
random();
Dhakshith
źródło
Lepiej byłoby ustawić zmienną myArrayy wewnątrz funkcji, aby nie zanieczyszczać globalnej przestrzeni nazw.
Neil Meyer
0

Moim zdaniem, lepiej niż zadzierać z prototypami lub zadeklarować go w samą porę, wolę wystawiać go na okno:

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

Teraz w dowolnym miejscu aplikacji możesz ją nazwać:

var rand = window.choice.call(array)

W ten sposób nadal możesz for(x in array)prawidłowo używać pętli

franki
źródło
1
Nie było mnie tutaj, gdy ktoś go ocenił i nie głosowałem, ale zgaduję, że wystawienie go na działanie okna jest po prostu deklaracją zmiennej globalnej. Zobacz: stackoverflow.com/questions/2613310/…
Chris
1
Nie powinieneś nigdy używać for...intablic, a nawet ogólnie. Ryzykujesz chodzeniem po łańcuchu prototypów. Dotyczy to również wszystkich właściwości obiektu, a nie wszystkich indeksów w tablicy. Jeśli chcesz użyć iteratora na tablicy, użyj for (var i = 0; i < foo.length; i++){}. Nawet lepiej, użyj czegoś takiego Array.prototype.forEach.
Robert
1
Nie wolę tego, ponieważ to zanieczyszcza globalny zasięg. Można powiedzieć, że może to być jedyna, ale da to nawyki naruszania tej dobrej praktyki.
Jekk
0

Znalazłem sposób na ominięcie komplikacji odpowiedzi, po prostu łącząc zmienną rand z inną zmienną, która umożliwia wyświetlanie tej liczby w wywołaniu myArray [] ;. Usuwając utworzoną nową tablicę i bawiąc się jej komplikacjami, wymyśliłem działające rozwiązanie:

<!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
źródło
Jestem zdezorientowany, dlaczego concatkiedykolwiek się tutaj zmienia ... randomsam nie zmienia tego i nic więcej nie jest wywoływane więcej niż raz ...
BalinKingOfMoria Przywróć CM
1
To rozwiązanie nie do końca ma sens. Dlaczego tworzysz zmienną o nazwie concat?
superluminarny
0

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

Ustawiasz stałą zmienną na tablicę, a następnie masz inną stałą, która wybiera losowo między trzema obiektami w tablicy, a następnie funkcja po prostu zwraca wyniki.

Neil Meyer
źródło
-1

Ogólny sposób uzyskiwania losowych elementów:

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
źródło
-1

randojs sprawia, że ​​jest to trochę prostsze i czytelniejsze:

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

Aaron Plocharczyk
źródło
1
Ciekawe: dlaczego opinie negatywne?
Leponzo
1
niektórzy ludzie nie są fanami pozyskiwania w bibliotekach kodu, który mogliby sami napisać, nawet gdyby to przyspieszyło i zwiększyło czytelność. jeśli biblioteka z jakiegoś powodu ulegnie awarii, Twoja strona internetowa ma teraz usterkę. randojs nie spada, ale nie wiedzą o tym, ponieważ nie jest tak dobrze znany jak biblioteki takie jak na przykład jQuery
Aaron Plocharczyk
-2

Oto przykład, jak to zrobić:

$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
źródło
-2

inna łatwa metoda:

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

var randomValue = myArray[Math.round((Math.random()*1000))%myArray.length];
Kamuran Sönecek
źródło
-3

Utwórz jedną losową wartość i przekaż do tablicy

Spróbuj wykonać następujący kod ..

//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
źródło
5
Ta odpowiedź wykorzystuje to samo rozwiązanie, co już zaakceptowana odpowiedź. Powinieneś powstrzymać się od dodawania tego samego rozwiązania dwa razy i zamiast tego przedstawiać tylko inne alternatywy, które mogłyby wnieść większy wkład w rozmowę.
Pixxl