1459
var items = Array(523, 3452, 334, 31, ..., 5346);

How do I get random item from items?

Kerem
  • 11,377
  • 5
  • 59
  • 58
James
  • 42,081
  • 53
  • 136
  • 161
  • 425
    the answer will not involve jQuery – Alnitak May 06 '11 at 17:51
  • 55
    I've never seen so many absolutely identical responses to a question... – Blindy May 06 '11 at 17:52
  • only this one involved numbers instead of months, eh? :-P – Kelly May 06 '11 at 17:57
  • 12
    This question is absolutely identical to [Getting random value from an array](http://stackoverflow.com/questions/4550505/getting-random-value-from-an-array), yet the Mighty Mods haven't bothered to close it in 3+ years. Instead, they close ["unconstructive" questions with hundreds of votes](http://stackoverflow.com/questions/10099059/what-are-the-key-differences-between-meteor-ember-js-and-backbone-js). – Dan Dascalescu Dec 16 '14 at 11:01
  • This now has more votes than the "unconstructive" question. –  Feb 22 '17 at 14:34
  • All answers to this problem are fundamentally wrong from what I can see and each basically just copy the others. What happens if the array has had elements deleted ([0],[1],[3],[4]...)? What happens if elements are added in way that keys are not an consistently incremented value but instead have some other meaning (such as a unique user id ([3453],[4316],[73698],[924]...). Are people so stuck on how to correctly use Math.random() that they are overlooking this? – JSON Sep 06 '18 at 04:35

13 Answers13

3016
var item = items[Math.floor(Math.random()*items.length)];
Corey
  • 6,612
  • 4
  • 20
  • 28
Kelly
  • 40,173
  • 4
  • 42
  • 51
  • 181
    **Math.random() will never be 1, nor should it.** The largest index should always be one less than the length, or else you'll get an `undefined` error. – Kelly Sep 16 '13 at 16:06
  • 37
    Elegant solution. I tested it: `var items = ["a","e","i","o","u"]` `var objResults = {}` `for(var i = 0; i < 1000000; i++){` `var randomElement = items[Math.floor(Math.random()*items.length)]` `if (objResults[randomElement]){` `objResults[randomElement]++` `}else{` `objResults[randomElement] = 1` `}` `}` `console.log(objResults)` The results are pretty randomized after 1000000 iterations: `Object {u: 200222, o: 199543, a: 199936, e: 200183, i: 200116}` – Johann Echavarria May 01 '14 at 22:17
  • I might be wrong, but I recall `var item = items[Math.random()*items.length>>0]` being slightly faster – vrugtehagel Jul 22 '16 at 12:31
  • 2
    What happens here when array is empty? – tomazahlin Oct 21 '16 at 16:02
  • Sorry, I must down vote this answer because: Use Math.round must more precisely than Math.floor. You can test on the console: Math.floor(Math.random()) => 0 Math.floor(Math.random()) => 0 Math.floor(Math.random()) => 0 Math.floor(Math.random()) => 0 Math.floor(Math.random()) => 0 Be careful. – christian Nguyen Dec 20 '16 at 09:38
  • 23
    @virus `Math.round` is not a valid substitution for `Math.floor`. Using `round` would cause accidentally referencing an undefined index, say in the case `Math.random()` is 0.95 and `items.length` is 5. `Math.round(0.95*5)` is 5, which would be an invalid index. `floor(random)` will always be zero in your example. – Kelly Dec 20 '16 at 14:43
  • 1
    @tomazahlin, if the array is empty, it will try to get item 0, which will fail. – Solomon Ucko Apr 02 '17 at 19:39
  • 32
    Nice answer. You can be shorter: `items[items.length * Math.random() | 0]` :) – aloisdg Mar 19 '18 at 17:20
  • 3
    @aloisdg that's true, as long as the array length is less than 2^31, which is still a very large number :) – Kelly Mar 21 '18 at 21:22
  • If you're using a Set, per the last comment, you don't have to look in the set to see if the currently selected element exists already. The Set won't contain duplicates. So you can just add every randomly chosen item to the Set. Then, if you want to make sure you have N items chosen, you can keep adding items until the size of the Set == N. – Reagankm Sep 17 '22 at 16:15
150

1. solution: define Array prototype

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

that will work on inline arrays

[2,3,5].random()

and of course predefined arrays

var list = [2,3,5]
list.random()

2. solution: define custom function that accepts list and returns element

function get_random (list) {
  return list[Math.floor((Math.random()*list.length))];
}


get_random([2,3,5])
JUDE DAILY
  • 132
  • 9
Dino Reic
  • 3,586
  • 3
  • 22
  • 11
  • 38
    @EvanCarroll better reference a useful link instead of downvoting for subjective notions such as coding style which does not make the answer invalid nor "unuseful" ! https://stackoverflow.com/questions/14034180/why-is-extending-native-objects-a-bad-practice – Simon Jul 14 '17 at 19:19
  • 33
    Upvoted because downvoting for adding something to Array.prototype is not useful to anyone without explanation. – AlexanderGriffin Nov 04 '18 at 18:20
  • 3
    The issue with adding a new function to Array.prototype is the same issue as adding a global variable - someone/something else may be using the same "name" for something different - which can cause subtle mahem – Schmoo Jun 27 '20 at 06:43
  • 1
    Thank you for this. Far more *usable* than typing the whole vanilla formula or calling a custom function when the code requires it more than once. As for the valid concerns about conflicts, that's what namespacing is for: `ns.` or `ns_` format where applicable. – OXiGEN Sep 21 '20 at 02:13
  • 2
    @Schmoo I just ran into one of those "subtle mayhem" situations. I shortened the prototype's name to "rand". Then suddenly during a `for (let i in arr)` loop, it iterates all the expected indexes, and also iterates an index of "rand". Had to switch to a `for (let i=0,l=arr.length;i – OXiGEN Sep 21 '20 at 09:24
  • 1
    Ditto @AlexanderGriffin. There is nothing wrong with adding to `Array.prototype` as long as the project doesn’t have to interact with other libraries or fight with other developers. There’s nothing _technically_ wrong with it anyway, but there might be logistic concerns where are the only real objections to that sort of thing. – Manngo Jul 12 '21 at 02:37
  • 1
    While we’re at it, we can always add the randomising method to the array itself: `items.random=function() {return this[Math.floor(Math.random()*this.length)];}`. This way you call the method as `items.random()` without getting into a religious war over tampering with prototypes. – Manngo Jul 12 '21 at 03:24
133

Use underscore (or loDash :)):

var randomArray = [
   '#cc0000','#00cc00', '#0000cc'
];

// use _.sample
var randomElement = _.sample(randomArray);

// manually use _.random
var randomElement = randomArray[_.random(randomArray.length-1)];

Or to shuffle an entire array:

// use underscore's shuffle function
var firstRandomElement = _.shuffle(randomArray)[0];
chim
  • 8,407
  • 3
  • 52
  • 60
  • 44
    Using underscore or lodash for just one function would be overkill, but if you're doing any complicated js functionality then it can save hours or even days. – chim Jan 07 '13 at 09:43
  • 1
    If the minimum value for underscore's `random` method is 0 it needs only the max value. [Docs here](http://underscorejs.org/#random) – Aaron Apr 03 '13 at 19:06
  • 26
    Nowadays underscore has also better choice for this ```_.sample([1, 2, 3, 4, 5, 6])``` – Mikael Lepistö Dec 03 '13 at 08:43
  • 7
    You will probably be using _ on any real project. It's not a bad thing. – superluminary Jul 14 '15 at 19:17
  • 9
    lodash is modularized on npm, so you can install just the `sample` function if you want: https://www.npmjs.com/package/lodash.sample – XåpplI'-I0llwlg'I - Dec 04 '15 at 11:32
  • 2
    `npm i -S lodash.sample` -- Love modular lodash w/browserify! – Roy Mar 10 '16 at 19:10
  • 8
    My creed is to use as few libraries as possible for any project. With that being said, I always end up using lodash. It's too convenient to not use – Max Phillips Dec 09 '16 at 20:21
  • 1
    My emoji, list and parenthesis interpreters all gave different results for `:)):`, so I don't quite understand the first line. –  Feb 22 '17 at 14:35
  • 1
    `_.shuffle(randomArray)[0];` This can return undefined values – Gimnath Mar 27 '22 at 02:34
109

If you really must use jQuery to solve this problem (NB: you shouldn't):

(function($) {
    $.rand = function(arg) {
        if ($.isArray(arg)) {
            return arg[$.rand(arg.length)];
        } else if (typeof arg === "number") {
            return Math.floor(Math.random() * arg);
        } else {
            return 4;  // chosen by fair dice roll
        }
    };
})(jQuery);

var items = [523, 3452, 334, 31, ..., 5346];
var item = jQuery.rand(items);

This plugin will return a random element if given an array, or a value from [0 .. n) given a number, or given anything else, a guaranteed random value!

For extra fun, the array return is generated by calling the function recursively based on the array's length :)

Working demo at http://jsfiddle.net/2eyQX/

Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • 3
    @neoascetic the point of that line is that picking an element from an array is not a jQuery problem, it's generic JS. – Alnitak Feb 10 '14 at 13:51
  • 120
    +1 for the fair dice roll! [For those poor souls who don't get the joke.](http://xkcd.com/221/) – The Guy with The Hat Aug 19 '14 at 13:16
  • @damd re: your proposed edit - it was clearly incorrect, since there's a clear split between _defining_ the plugin in the IIFE, and using the plugin. However for consistency I have replaced the `$` in the usage line with `jQuery`. – Alnitak Mar 04 '16 at 15:54
  • 5
    Definitely. There are less than an average of 3 chained methods per line, and the `$` is not being used at least once per each line, therefore it does not have enough jQuery. –  Feb 22 '17 at 14:47
  • 2
    This is not a problem that requires jQuery. – robertmain Feb 01 '19 at 14:57
  • @robertmain see first line – Alnitak Feb 01 '19 at 15:17
  • I saw it. I'm still sticking with my comment. This problem does not require jQuery. Any more than addition, string concatenation, variable interpolation or sorting does. – robertmain Feb 01 '19 at 16:43
  • 1
    https://needsmorejquery.com/ – easrng May 06 '20 at 01:12
  • return 4.... Not only that, but you NEVER "have to use jQuery", it's not a tool that is in the space where it solves things nothing else can any more. – MrMesees Aug 23 '20 at 07:54
74

Here's yet another way:

function rand(items) {
    // "~~" for a closest "int"
    return items[~~(items.length * Math.random())];
}

Or as recommended below by @1248177:

function rand(items) {
    // "|" for a kinda "int div"
    return items[items.length * Math.random() | 0];
}
Kerem
  • 11,377
  • 5
  • 59
  • 58
  • 46
    What is that crazy `~~`? Never seen that in JS before. – Sam Stern Nov 22 '14 at 22:20
  • 10
    @hatboysam: [do a search](http://stackoverflow.com/questions/4055633/what-does-double-tilde-do-in-javascript) - it essentially converts the operand to the closest integer. – Dan Dascalescu Dec 16 '14 at 11:10
  • 9
    Actually, it rounds it down, like `Math.floor`. –  Feb 22 '17 at 14:36
  • 20
    Nice answer. You still can be shorter: `items[items.length * Math.random() | 0]` :) – aloisdg Mar 19 '18 at 17:19
  • 16
    "Actually, it rounds it down, like Math.floor" @programmer5000. It actually rounds towards 0, i.e. ~~(-1.5) evaluates to -1, not the -2 which Math.floor gives. – ProfDFrancis Jul 22 '18 at 16:08
  • `~~5.999999999999999` outputs `5` whereas `~~5.9999999999999999` outputs `6`... heh – evolutionxbox Aug 29 '20 at 17:08
  • @SamStern `~~` is a trick to remove decimals by converting a number to an integer. See https://stackoverflow.com/questions/4055633/what-does-double-tilde-do-in-javascript#answer-4055675 – Manngo Jul 12 '21 at 02:45
  • @evolutionxbox That’s due to a round off error that you get with JavaScript. It’s similar to the notorious `0.1+0.2` error. Remember that decimals, being based on `2`s and `5`s often convert to recurring “binary decimals” (bicimals?) since binary is based only on `2`s. – Manngo Jul 12 '21 at 02:48
  • ~ is a bitwise NOT operator: [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT). Here it is used twice, similar like `!!some_variable`. – cezar Oct 10 '21 at 07:30
53
var random = items[Math.floor(Math.random()*items.length)]
gen_Eric
  • 223,194
  • 41
  • 299
  • 337
22
// 1. Random shuffle items
items.sort(function() {return 0.5 - Math.random()})

// 2. Get first item
var item = items[0]

Shorter:

var item = items.sort(function() {return 0.5 - Math.random()})[0];

Even shoter (by José dB.):

let item = items.sort(() => 0.5 - Math.random())[0];
Ivan Pirog
  • 2,982
  • 1
  • 17
  • 7
22

jQuery is JavaScript! It's just a JavaScript framework. So to find a random item, just use plain old JavaScript, for example,

var randomItem = items[Math.floor(Math.random()*items.length)]
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
planetjones
  • 12,469
  • 5
  • 50
  • 51
16
var rndval=items[Math.floor(Math.random()*items.length)];
Blindy
  • 65,249
  • 10
  • 91
  • 131
9
var items = Array(523,3452,334,31,...5346);

function rand(min, max) {
  var offset = min;
  var range = (max - min) + 1;

  var randomNumber = Math.floor( Math.random() * range) + offset;
  return randomNumber;
}


randomNumber = rand(0, items.length - 1);

randomItem = items[randomNumber];

credit:

Javascript Function: Random Number Generator

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
neebz
  • 11,465
  • 7
  • 47
  • 64
6

If you are using node.js, you can use unique-random-array. It simply picks something random from an array.

Aayan L
  • 77
  • 1
  • 6
2

An alternate way would be to add a method to the Array prototype:

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

 var teams = ['patriots', 'colts', 'jets', 'texans', 'ravens', 'broncos']
 var chosen_team = teams.random(teams.length)
 alert(chosen_team)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
James Daly
  • 1,357
  • 16
  • 26
  • 4
    arrays have a built-in length property - why pass it as a parameter?! – Alnitak Dec 24 '12 at 18:22
  • 1
    i guess my point is that you can pass in any length you want not just the length of the array - if you just wanted to randomize the first two entries you could put length as 2 without changing the method. I don't think there is a performance issue with passing the length property as a parameter but i may be wrong – James Daly Dec 24 '12 at 19:15
  • 3
    It is generally not a good idea to extend host objects like this. You risk tripping over a future implementation of `Array.random` by the client that behaves differently than yours, breaking future code. You could at least check to make sure it doesn't exist before adding it. – Chris Baker Aug 19 '14 at 18:36
1
const ArrayRandomModule = {
  // get random item from array
  random: function (array) {
    return array[Math.random() * array.length | 0];
  },

  // [mutate]: extract from given array a random item
  pick: function (array, i) {
    return array.splice(i >= 0 ? i : Math.random() * array.length | 0, 1)[0];
  },

  // [mutate]: shuffle the given array
  shuffle: function (array) {
    for (var i = array.length; i > 0; --i)
      array.push(array.splice(Math.random() * i | 0, 1)[0]);
    return array;
  }
}
np42
  • 847
  • 7
  • 13
  • Pointed out in many comments, this is a bad practice, please refer to https://stackoverflow.com/questions/14034180/why-is-extending-native-objects-a-bad-practice :) – benftwc Aug 28 '18 at 00:12
  • I just change the declaration to avoid showing bad pactice method declaration – np42 Aug 29 '18 at 15:52