从Javascript对象中选择随机属性


88

假设您有一个像{'cat':'meow','dog':'woof'...}这样的Javascript对象,比我想出的这种漫长的方法,有没有更简洁的方法可以从对象中选择随机属性:

function pickRandomProperty(obj) {
    var prop, len = 0, randomPos, pos = 0;
    for (prop in obj) {
        if (obj.hasOwnProperty(prop)) {
            len += 1;
        }
    }
    randomPos = Math.floor(Math.random() * len);
    for (prop in obj) {
        if (obj.hasOwnProperty(prop)) {
            if (pos === randomPos) {
                return prop;
            }
            pos += 1;
        }
    }       
}

OP,请重新选择您选择的答案... @kennytm在其他人之前正确回答了它。大卫的答案很简单,就是编码不好(尽管它可以工作)
vsync

请注意,问题和答案实际上是在寻找返回随机对象属性的值,而不是问题标题所建议的随机属性的值
kontur

Answers:


181

选择的答案会很好。但是,此答案将运行得更快:

var randomProperty = function (obj) {
    var keys = Object.keys(obj);
    return obj[keys[ keys.length * Math.random() << 0]];
};

3
这样做更好,因为它不使用循环
Dominic 2014年

13
我进行了一些测试,看来选择的答案很好用,并且属性的选择没有偏见(与回答之间的推测相反);但是,我在具有170,000个键的对象上进行了测试,此处的解决方案的速度约为所选解决方案的两倍。
蜻蜓2014年

8
<< 0(左移0)是编写Math.round()的简便方法吗?
SystemicPlural 2014年

4
此jsperf jsperf.com/random-object-property-selection 基准测试了此答案和所选答案。对于较小的对象(100个属性),此答案的性能提高了3倍。较大的对象(100k属性)的差异降低了2倍。
Constablebrew

2
@MuhammadUmer-No.Math.random()返回范围为[0,1)的数字。
Yay295

74

从流中选择随机元素

function pickRandomProperty(obj) {
    var result;
    var count = 0;
    for (var prop in obj)
        if (Math.random() < 1/++count)
           result = prop;
    return result;
}

2
ECMAScript标准是否说明有关始终以相同顺序遍历的属性?在大多数实现对象有稳定的订单,但这种行为是未定义的规格:stackoverflow.com/questions/280713/...
布伦丹·伯格

4
这似乎朝对象中的第一个元素倾斜。我还不知道为什么!
科尔·格里森

7
这将永远不会选择第一个属性(Math.random总是<1),此后每个数字都有0.5的机会被选中。所以0.5第二属性,0.25进行第3,0.125为第四等
SystemicPlural

4
某些更正:此函数可以选择第一个属性。在第一次迭代中,计数的前缀增量使方程式的右边评估为1/1 ==1。由于Math.random始终在[0,1)范围内(零到一,不包括一个),该表达式的计算结果为true,并且选择了第一个属性。就随机选择的分布而言,它是均匀的。一个属性有100%的机会被选中。如果有两个,则有50%的机会被选中。与三分之33.3%。等等。该解决方案具有最小的内存占用量。
Constablebrew

3
@davidhadas考虑三个元素的序列。选择第一个元素的可能性为1。但是,第二个元素可能以1/2的概率替换了它(注意,我们不会立即返回!)。第二个元素可能会被第三个元素替换,概率为1/3。所以我们得到P(第一)= P(第一被选择)* P(第二未被选择)* P(第三未被选择)= 1 * 1/2 * 2/3 = 1/3; P(第二)= P(第二次选择)* P(第三次未选择)= 1/2 * 1/3 = 1/3; P(第三)= P(第三次选择)= 1/3。
马丁·托恩沃尔(MartinTörnwall)

19

我不认为任何示例都足以使您感到困惑,因此这是一个很难读懂的示例,它做同样的事情。

编辑:除非您希望您的同事讨厌您,否则您可能不应该这样做。

var animals = {
    'cat': 'meow',
    'dog': 'woof',
    'cow': 'moo',
    'sheep': 'baaah',
    'bird': 'tweet'
};

// Random Key
console.log(Object.keys(animals)[Math.floor(Math.random()*Object.keys(animals).length)]);

// Random Value
console.log(animals[Object.keys(animals)[Math.floor(Math.random()*Object.keys(animals).length)]]);

说明:

// gets an array of keys in the animals object.
Object.keys(animals) 

// This is a number between 0 and the length of the number of keys in the animals object
Math.floor(Math.random()*Object.keys(animals).length)

// Thus this will return a random key
// Object.keys(animals)[0], Object.keys(animals)[1], etc
Object.keys(animals)[Math.floor(Math.random()*Object.keys(animals).length)]

// Then of course you can use the random key to get a random value
// animals['cat'], animals['dog'], animals['cow'], etc
animals[Object.keys(animals)[Math.floor(Math.random()*Object.keys(animals).length)]]

长手,减少混乱:

var animalArray  = Object.keys(animals);
var randomNumber = Math.random();
var animalIndex  = Math.floor(randomNumber * animalArray.length);

var randomKey    = animalArray[animalIndex];
// This will course this will return the value of the randomKey
// instead of a fresh random value
var randomValue  = animals[randomKey]; 

4
这其实是最合理的解决方案
帕维尔

2
我最喜欢它,并附带解释和所有内容,还包括一个实际示例POJO。好答案,值得更多的赞扬!只是使一切都更容易理解!
Tigerrrrr

1
最好的解决方案!这应该是投票最多的。
nilsoviani

15

您可以在遍历对象时构建一系列键。

var keys = [];
for (var prop in obj) {
    if (obj.hasOwnProperty(prop)) {
        keys.push(prop);
    }
}

然后,从键中随机选择一个元素:

return keys[keys.length * Math.random() << 0];

13
Object.keys在这里很有用var keys = Object.keys(obj)
2013年

Dang <<比使用Math.floor()更优雅,可能也更便宜。我真的得站下来学习如何使用那些按位运算符。
Paul J

5
在这种情况下,按位运算符的使用很可能会被破解,因为它需要一个整数作为输入,它会转换数字。应用于<< 0整数将无济于事。parseInt()将做同样的工作。因此,除了编写难懂的代码外,这里没有什么可学的。
landunder

13

如果您有能力使用库,则可能会发现Lo-Dash JS库有很多针对此类情况的非常有用的方法。在这种情况下,请继续检查_.sample()

(请注意,Lo-Dash约定将命名库对象_。不要忘记在同一页面中检查安装以为您的项目进行安装。)

_.sample([1, 2, 3, 4]);
// → 2

对于您的情况,请继续使用:

_.sample({
    cat: 'meow',
    dog: 'woof',
    mouse: 'squeak'
});
// → "woof"

3

如果您使用的是underscore.js,则可以执行以下操作:

_.sample(Object.keys(animals));

额外:

如果需要多个随机属性,请添加一个数字:

_.sample(Object.keys(animals), 3);

如果只需要具有这些随机属性的新对象:

const props = _.sample(Object.keys(animals), 3);
const newObject = _.pick(animals, (val, key) => props.indexOf(key) > -1);

0

做到这一点的另一种简单方法是定义一个应用Math.random()函数的函数。

此函数返回一个随机整数,范围从“ min”开始

function getRandomArbitrary(min, max) {
  return Math.floor(Math.random() * (max - min) + min);
}

然后,每次将上述函数作为参数提供时,从Javascript对象中提取“键”或“值”或“两者”。

var randNum = getRandomArbitrary(0, 7);
var index = randNum;
return Object.key(index); // Returns a random key
return Object.values(index); //Returns the corresponding value.

您是说Object.values(someObject)[index]吗?
Bemmu

我用来存储生成的随机数的index变量只是一个容器,没什么特别的。如果没有将生成的数字存储到另一个变量中,则函数的每个实例每次调用都会生成一个新的随机数。getRandomArbitrary
Sushant Chaudhary

0

在JSON对象中,您必须将其放置:

var object={
  "Random": function() {
    var result;
    var count = 0;
    for (var prop in this){
      if (Math.random() < 1 / ++count&&prop!="Random"){
        result = this[prop];
      }
    }
    return result;
  }
}

该函数将返回随机属性的内部。


0

您可以使用以下代码从JavaScript对象中选择一个随机属性:

function randomobj(obj) {
var objkeys = Object.keys(obj)
return objkeys[Math.floor(Math.random() * objkeys.length)]
}
var example = {foo:"bar",hi:"hello"}
var randomval = example[randomobj(example)] // will return to value
// do something

尽管此代码可以回答问题,但提供有关如何和/或为什么解决问题的其他上下文将提高​​答案的长期价值。
Nic3500 '18
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.