【问题标题】:Pick random property from a Javascript object从 Javascript 对象中选择随机属性
【发布时间】:2011-02-01 16:45:20
【问题描述】:

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

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

【问题讨论】:

  • 请注意,问题和答案实际上是在寻找返回随机对象属性的,而不是问题标题所暗示的随机属性。

标签: javascript random


【解决方案1】:

选择的答案会很好用。但是,这个答案会运行得更快:

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

【讨论】:

  • 这样更好,因为它不使用循环
  • 我做了一些测试,似乎选择的答案工作得很好,并且属性的选择是公正的(与响应中的猜测相反);但是,我在一个具有 170,000 个键的对象上进行了测试,这里的解决方案大约是所选解决方案的两倍。
  • 这个 jsperf jsperf.com/random-object-property-selection 对这个答案和选择的答案进行了基准测试。对于较小的对象(100 个属性),此答案的性能提高了 3 倍。较大的对象(100k 属性)差异下降到 2 倍。
  • @MuhammadUmer - 否。Math.random() 返回范围 [0,1) 中的数字。
【解决方案2】:

Picking a random element from a stream

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

【讨论】:

  • ECMAScript 标准是否说明了始终以相同顺序遍历的属性?大多数实现中的对象具有稳定的顺序,但规范中未定义行为:stackoverflow.com/questions/280713/…
  • 这似乎偏向对象中的第一个元素。我还没弄明白为什么!
  • 这将永远不会选择第一个属性(Math.random 总是
  • 一些更正:此功能可以选择第一个属性。在第一次迭代中,count 的前缀增量使等式的右侧计算为 1/1 == 1。由于 Math.random 始终在 [0,1) 范围内(从零到一,不包括一),表达式的计算结果为真,并选择了第一个属性。就随机选择的分布而言,它是均匀的。对于一个属性,它有 100% 的机会被选中。如果有两个,则有 50% 的机会选择其中一个。以三分之33.3%。等等。此解决方案的内存占用最少。
  • @davidhadas 考虑三个元素的序列。第一个被选中的概率为 1。但是,它可能会被第二个元素以 1/2 的概率替换(注意我们不会立即返回!)。第二个元素可能依次被第三个元素替换,概率为 1/3。所以我们得到 P(first) = P(firstpicked) * P(second notpicked) * P(third notpicked) = 1 * 1/2 * 2/3 = 1/3; P(第二个) = P(第二个选择) * P(第三个未选择) = 1/2 * 1/3 = 1/3; P(第三个)= P(第三个选择)= 1/3。
【解决方案3】:

我认为这些示例中的任何一个都不够令人困惑,所以这里有一个非常难以阅读的示例做同样的事情。

编辑:你可能不应该这样做,除非你想让你的同事讨厌你。

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

【讨论】:

  • 我最喜欢这个,有解释和一切,还包括一个实际的例子 POJO。好答案,值得更多赞!只是让一切变得更容易理解!
【解决方案4】:

如果你会使用库,你可能会发现Lo-Dash JS 库有很多非常有用的方法来解决这种情况。在这种情况下,请继续检查_.sample()

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

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

在你的情况下,继续使用:

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

【讨论】:

    【解决方案5】:

    您可以在遍历对象时构建一个键数组。

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

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

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

    【讨论】:

    • Object.keys 在这里很有用 var keys = Object.keys(obj)
    • 在这种情况下,按位运算符的使用更可能是一种 hack,因为它需要一个整数作为输入,它会转换数字。将&lt;&lt; 0 应用于整数将无济于事。 parseInt() 会做同样的工作。因此,除了编写不太容易理解的代码之外,这里没有什么可学的。
    【解决方案6】:

    如果您使用的是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);
    

    【讨论】:

      【解决方案7】:

      您可以使用以下代码从 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
      

      【讨论】:

      • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。
      【解决方案8】:

      另一种简单的方法是定义一个应用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]?
      • 我用来存储生成的 random 数字的 index 变量只是一个容器,没什么特别的。如果我没有将生成的数字存储到另一个变量中,那么函数 getRandomArbitrary 的每个实例都会在每次调用时生成一个新的随机数。
      【解决方案9】:

      这里有很多很棒的答案,所以让我试着在它的双重麻烦变体中传播按位 NOT (~) 运算符的意识(我很确定我已经了解了在 StackOverflow 上,无论如何)。

      通常,您会像这样从 1 到 10 中选择一个随机数:

      Math.floor(Math.random()*10) + 1
      

      但按位运算意味着舍入完成得更快,因此假设您正在执行足够多的这些操作,那么以下实现可能会显着提高性能:

      ~~(Math.random()*10) + 1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-15
        • 2012-11-01
        • 1970-01-01
        • 2020-02-10
        • 2018-09-16
        相关资源
        最近更新 更多