Отримання випадкового значення з масиву JavaScript


793

Поміркуйте:

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

Як я можу вибрати випадкове значення з цього масиву за допомогою JavaScript?

Відповіді:


1479

Це простий однолінійний

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

Приклад

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 це правильно. Зверніть увагу на Math.floor(Math.random(...))виклик, який завершується вниз.
ashes999

33
А-а, я дізнався щось нове. Я обговорював випадок, коли він дорівнює ТАКІ 1, але, мабуть, (за даними W3Schools) Math.random становить від 0 включно до 1 ексклюзив. Моє ліжко.
SapphireSun

13
Я можу помилятися, але я пам'ятаю, var rand = myArray[Math.random() * myArray.length>>0]що трохи швидше
vrugtehagel

6
на всякий випадок, якщо ви вже використовуєте lodash, ви можете використовувати _.sample (масив)
Габріель Матусевич

2
Я віддаю перевагу такому варіанту:var rand = myArray[Math.random() * myArray.length | 0]
Nicolas

76

Якщо у вашому проекті вже є підкреслення або подання, ви можете використовувати його _.sample.

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

Якщо вам потрібно отримати більше одного елемента випадковим чином, ви можете передати це як другий аргумент у підкресленні:

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

або використовувати _.sampleSizeметод у lodash:

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

Під час використання typecript: майте на увазі, що тип повернення буде "string | undefined" замість "string", що задається рядковим масивом.
Стефан Шильке

23

Метод прототипу

Якщо ви плануєте багато отримувати випадкове значення, ви можете визначити функцію для нього.

Спочатку покладіть це у свій код десь:

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

Зараз:

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

Код, випущений у загальнодоступне надбання на умовах ліцензії CC0 1.0 .


І це робить що?
Кен Шарп

3
@KenSharp дозволяє зателефонувати .sample()на будь-який масив, щоб отримати випадковий предмет
Бен Аубін

5
Слід уникати поширення нативних типів об'єктів. Я видалив свою відповідь, побачивши, що це було дуже схвалено, але пропагую погану практику. Більш детальне обговорення цього питання див , наприклад stackoverflow.com/questions/14034180 / ... і eslint.org/docs/rules/no-extend-native
Markus Амальтея Магнусон

20

~~набагато швидше Math.Floor(), тому, коли справа доходить до оптимізації продуктивності, створюючи вихід з використанням елементів інтерфейсу, ~~виграє гру. БІЛЬШЕ ІНФОРМАЦІЇ

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

Але якщо ви знаєте, що в масиві буде мільйони елементів, ніж ви можете переглядати між оператором Bitwise і Math.Floor(), як бітовий оператор дивно поводиться з великою кількістю. Дивіться нижче приклад, пояснений з результатом. БІЛЬШЕ ІНФОРМАЦІЇ

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

1
Посилання мертва, як би цікавий пост, і я буду використовувати це більше, ніж Math.floorзараз :)
aabbccsmith

використання оператора "побіт не", але швидше - це не читабельно, тому вам доведеться вибрати те, що для вас важливіше
Мацей Урбанський

16

Скажіть, ви хочете вибрати випадковий предмет, який відрізняється від останнього часу (насправді не випадковий, але все ж загальна вимога) ...

Спираючись на відповідь @Markus, ми можемо додати ще одну функцію прототипу:

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

І реалізуйте так:

var myRandomDiffElement = myArray.randomDiffElement(lastRandomElement)

11

Якщо у вас є фіксовані значення (наприклад, список назв місяця) і ви хочете однорядне рішення

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

Друга частина масиву - це операція доступу, як описано в Чому [5,6,8,7] [1,2] = 8 в JavaScript?


2
Такий код є поганою і шкідливою практикою. Його ніколи не слід використовувати у виробництві. Він має низьку читабельність і має жорстко кодовану довжину масиву. Людина, що змінює вхід масиву, може в кінці кінця забути відредагувати тверду коду.
Чайка

@Seagull OP ніколи не просив конкретного середовища. Також цей коментар є безглуздим, оскільки його можна було б застосувати майже до всіх відповідей на це питання;)
IG Pascual

Але більшість людей приходять до цього питання з пошуку Google, і вони можуть використовувати рішення в інших сценаріях, ніж оригінальна ОП.
Чайка

@Seagull Haha люди вільні вирішувати, який підхід використовувати, я не є чітким кодом керівництва!
IG Pascual

10

Найкоротша версія:

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

Що робить | 0?
Кен Шарп

2
Він перетворить Float на Int, такий же, як Math.floor.
foxiris

4
| 0Сам @KenSharp - це побітова операція, яка нічого не робить, але в JavaScript поплавці перетворюються на ints перед будь-якою побітовою операцією . Тож це щось на кшталт того, як + ''насправді нічого не робить, але може використовуватися для перетворення речей у рядки.
дшеферд

Це не те саме, Math.floorале тут правильно робити. Це оператор, тому це швидше, ніж Math.floorхоча б тому, що в будь-який час під час виконання деякого коду можна зробити, Math.floor = someOtherFunctionі вони не можуть зробити те ж саме для '|'. З іншого боку, що стосується Math.floorта |відрізняються від спроб Math.floor(-1.5)проти -1.5 | 0. До речі, вам не потрібні дужки. |має дуже низький пріоритет.
gman

7

Якщо ви хочете , щоб написати його на одній лінії, як рішення Паскуаль, в інше рішення було б написати його з допомогою функції пошуку ES6 в (на підставі того, що ймовірність випадкового вибору одного з nелементів є 1/n):

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

Використовуйте такий підхід для тестування, і якщо є вагомі причини не зберігати масив лише в окремій змінній. Інакше інші відповіді ( floor(random()*lengthі використання окремої функції) - ваш шлях.


Дуже оригінальне рішення. Чудова робота! До речі, єдине справжнє та динамічне однолінійне рішення тут.
Славік Мельцер

7

Faker.js має багато корисних функцій для генерування випадкових даних тесту. Це хороший варіант у контексті тестового набору:

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

Як згадували коментатори, ви зазвичай не повинні використовувати цю бібліотеку у виробничому коді.


8
Для такої простої проблеми, як ця, додавання залежності для всієї бібліотеки є непотрібним і додає до розширення коду. Якщо що-небудь, ви потенційно можете порекомендувати фактичний метод, з Fakerякого вибирається елемент випадкового масиву.
Pixxl

1
"Проста проблема", як ця, зазвичай вирішується бібліотеками, які пропонують просте рішення проблеми, з якою вже стикалися сотні людей. Ці бібліотеки, як правило, надійні та добре налагоджені та мають справу з різними застереженнями, які ми не хочемо повторно реалізовувати. Зазвичай це ситуація, коли я рекомендую використовувати бібліотеку.
smonff

Тоді вам слід просто скопіювати цей метод із бібліотеки та помістити його у файл утиліти
Rick Bross,

Поради щодо того, що бібліотеки слід оцінювати за вагою сторінки / ваги WRT-сторінки під час їх надсилання до веб-браузера, є надійною порадою, і я від усієї душі погоджуюся, що доставка Faker.js до браузера була б смішною. Однак питання не зазначає, який час виконання JS використовується. Для технологій виконання, що базуються на NodeJS, цілком більш важкі залежності, це стосується випадків, коли я використовую Faker.js - у тестових наборах для огірків JS.
Натан

6

Редагування прототипу масиву може бути шкідливим. Тут це проста функція.

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
}

Використання:

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

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

3

Рекурсивна, окрема функція, яка може повертати будь-яку кількість елементів (ідентичну 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

Для отримання крипто-сильних випадкових елементів використовується масив форм

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

Це схоже на рішення, але більш загальне, ніж рішення @Jacob Relkin:

Це ES2015:

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

Код працює, вибираючи випадкове число між 0 і довжиною масиву, а потім повертає елемент у цьому індексі.


1

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

або еквівалентна коротша версія:

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

Приклад коду:

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


1

Проста функція:

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

АБО

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

АБО

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

Було б краще встановити змінну myArrayy всередині вашої функції, щоб вона не забруднювала глобальну область імен.
Ніл Мейєр

0

На мою думку, краще, ніж возитися з прототипами чи декларувати його вчасно, я вважаю за краще виставляти його до вікна:

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

Тепер будь-де у вашому додатку ви називаєте це так:

var rand = window.choice.call(array)

Таким чином, ви все ще можете for(x in array)правильно використовувати цикл


1
Я не був тут, коли хто-небудь спричинив це, і я не спровокував це, але я здогадуюсь, що виставлення цього вікна в основному оголошує глобальну змінну. Дивіться: stackoverflow.com/questions/2613310/…
Кріс

1
Ви ніколи не повинні використовувати for...inна масивах, або навіть взагалі. Ви ризикуєте пройти ланцюжок прототипу. Він також призначений для всіх властивостей об'єкта, а не для всіх індексів масиву. Якщо ви хочете використовувати ітератор у масиві, використовуйте for (var i = 0; i < foo.length; i++){}. Ще краще використовувати Array.prototype.forEachзамість цього щось подібне .
Роберт

1
Я не віддаю перевагу цьому, оскільки це забруднює глобальну сферу. Ви можете сказати, що це може бути лише один, але це дасть звички порушувати цю добру практику.
Джек

0

Я знайшов шлях навколо ускладнень верхньої відповіді, просто приєднавши rand змінної до іншої змінної, яка дозволяє відображати це число всередині виклику myArray [] ;. Видаливши новий створений масив і пограбуючи з його ускладненнями, я придумав робоче рішення:

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

Я розгублений, чому concatтут колись змінюється ... randomсам не змінюється, і більше нічого не викликають більше, ніж один раз ....
BalinKingOfMoria Reinstate CMs

1
Це рішення не зовсім має сенс. Чому ви створюєте змінну під назвою concat?
надсвітні

0

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

Ви встановлюєте постійну змінну для масиву, потім у вас є інша константа, яка вибирає випадковим чином між трьома об'єктами в масиві, а потім функція просто повертає результати.


-1

Загальний спосіб отримання випадкових елементів:

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

randojs робить це трохи простіше і читабельніше:

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


1
Просто цікаво: навіщо низовини?
Лепонцо

1
деякі люди не є прихильником пошуку джерел у бібліотеках за кодом, який вони могли б написати самі, навіть якщо це зробило б речі швидшими і читабельнішими. якщо бібліотека з якихось причин виходить з ладу, зараз на вашому веб-сайті спостерігаються збої. randojs не опускається, але вони цього не знають, оскільки це не так відомо, як, наприклад, бібліотеки, як jQuery
Aaron Plocharczyk,

-2

Ось приклад того, як це зробити:

$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

ще один простий метод:

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

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

-3

Створіть одне випадкове значення та перейдіть до масиву

Спробуйте наступний код ..

//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
Ця відповідь використовує те саме рішення, що і вже прийнята відповідь. Вам слід утримуватися від додавання одного і того ж рішення двічі, а натомість лише запропонувати можливі інші варіанти, які б більше сприяли розмові.
Pixxl
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.