从JavaScript数组获取随机值


791

考虑:

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

如何使用JavaScript从此数组中选择随机值?

Answers:


1478

这是一个简单的单线

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 2014年

32
啊,我学到新东西了。我在讨论它等于1的情况,但显然(根据W3Schools)Math.random在0包含和1排除之间。我的错。
SapphireSun

13
我可能是错的,但我记得var rand = myArray[Math.random() * myArray.length>>0]速度稍快
vrugtehagel

6
以防万一,如果您已经在使用lodash,则可以使用_.sample(array)
Gabriel Matusevich

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

或使用_.sampleSizelodash中的方法:

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

使用打字稿时:请注意,给定字符串数组,返回类型将是“ string | undefined”而不是“ string”。
Stephan Schielke

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()任何数组以获得随机项
Ben Aubin

5
应避免扩展本机对象类型。我删除了我的答案,因为看到了很多建议,但提倡不良做法。有关此问题的更多讨论,请参见例如stackoverflow.com/questions/14034180/…eslint.org/docs/rules/no-extend-native
Markus Amalthea Magnuson

20

~~速度比快得多Math.Floor(),因此在使用UI元素生成输出时进行性能优化时,就可以~~赢得比赛。更多信息

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

但是,如果您知道该数组将拥有数百万个元素,那么您可能需要重新考虑按位运算符和Math.Floor(),因为按位运算符对大量数字的行为很奇怪。参见下面的示例,其中对输出进行了说明。更多信息

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

1
链接已死,但是有趣的帖子,我将比Math.floor现在更多地使用它:)
aabbccsmith

使用“按位非”运算符虽然速度更快,但可读性不强,因此您必须选择对您更重要的内容
MaciejUrbański,

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

数组的第二部分是访问操作,如JavaScript为什么[5,6,8,7] [1,2] = 8中所述?


2
这样的代码是一种坏习惯。切勿在生产中使用它。它具有较低的可读性,并且具有硬编码的数组长度。更改数组输入的人员可能会忘记最后编辑硬编码的长度。
海鸥

@Seagull OP从未要求特定的环境。同样,此评论也没有意义,因为它可以应用于该问题的几乎所有答案;)
IG Pascual,

但是大多数人都是通过Google搜索解决这个问题的,他们可能会在原始OP之外的其他情况下使用该解决方案。
海鸥

@Seagull Haha人们可以自由决定使用哪种方法,我不是清洁代码准则的常见问题!
IG Pascual,

10

最短的版本:

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

怎么| 0办?
肯·夏普

2
与Math.floor相同,它将Float转换为Int。
foxiris

4
@KenSharp | 0本身是按位操作,不执行任何操作,但是在javascript中,浮点数会在任何按位操作之前转换为ints。因此,这有点像是什么+ ''都不做,但是可以用来将其转换为字符串。
dshepherd '18

这不尽相同,Math.floor但这是正确的做法。它是一个运算符,因此它的运行速度比Math.floor仅因为在运行代码的任何时候都可以Math.floor = someOtherFunction并且它们不能对'|'做相同的情况下要快。在另一方面,作为Math.floor|是不同的尝试Math.floor(-1.5)VS -1.5 | 0。顺便说一下,您不需要括号。|优先级很低。
gman

7

如果要像Pascual的解决方案一样将其写在一行上,另一种解决方案是使用ES6的find函数来编写它(基于以下事实:从n项目中随机选择一个的概率为1/n):

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

如果有充分理由不将数组仅保存在单独的变量中,请使用该方法进行测试。否则,其他答案(floor(random()*length以及使用单独的函数)是您要走的路。


非常原始的解决方案。做得好!顺便说一句,这里是唯一真正且动态的单线解决方案。
Slavik Meltser

7

Faker.js具有许多实用程序功能,用于生成随机测试数据。在测试套件的上下文中,这是一个不错的选择:

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

正如评论者提到的那样,通常不应在生产代码中使用此库。


8
对于像这样的简单问题,不需要为整个库添加依赖项,这会使代码膨胀。如果有的话,您可能会建议Faker从中选择随机数组元素的实际方法。
Pixxl

1
像这样的“简单问题”通常由图书馆解决,该图书馆为数百人已经面临的问题提供了简单的解决方案。这些库通常是健壮且调试良好的,并且处理了我们不想重新实现的各种警告。我通常会建议使用库。
smonff

比您应该只从库中复制一个方法并将其放入utils文件中
Rick Bross '18

关于将库运送到Web浏览器时应评估WRT页面成本/收益的建议是合理的建议,我全心全意地同意将Faker.js运送到浏览器是荒谬的。但是,该问题未提及正在使用哪个JS运行时。对于基于NodeJS的运行时,较重的依赖性是完全合理的,在Cucumber JS测试套件中,我使用Faker.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])
}


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
当有人对它进行投票时,我不是在这里,也没有对它进行投票,但我的猜测是,将其暴露给window基本上是在声明全局变量。参见:stackoverflow.com/questions/2613310/…–
克里斯(Chris)

1
您永远不应该for...in在数组上使用,甚至一般而言。您冒着走原型链的风险。这也意味着对象的所有属性,而不是数组中的所有索引。如果要在数组上使用迭代器,请使用for (var i = 0; i < foo.length; i++){}。更好的是,改用类似的东西Array.prototype.forEach
罗伯特

1
我不喜欢这样做,因为它会污染全球范围。您可能会说这可能是唯一的一种,但是会养成违反该良好做法的习惯。
Jekk '16

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恢复CM的

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
只是好奇:为什么要投票?
Leponzo

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.