从 Javascript 对象中选择随机属性

IT技术 javascript random
2021-02-07 05:42:59

假设你有一个像 {'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;
        }
    }       
}
6个回答

选择的答案将运作良好。但是,这个答案会运行得更快:

var randomProperty = function (obj) {
    var keys = Object.keys(obj);
    return obj[keys[ keys.length * Math.random() << 0]];
};
我做了一些测试,似乎选择的答案效果很好,并且属性的选择是无偏见的(与响应中的推测相反);但是,我在一个具有 170,000 个键的对象上进行了测试,这里的解决方案大约是所选解决方案的两倍。
2021-03-14 05:42:59
这更好,因为它不使用循环
2021-03-20 05:42:59
<< 0(向左移动 0 位)是编写 Math.round() 的速记方法吗?
2021-03-22 05:42:59
@MuhammadUmer - 不Math.random()返回 [0,1) 范围内的数字。
2021-04-01 05:42:59
此 jsperf jsperf.com/random-object-property-selection 对此答案和所选答案进行了基准测试。对于较小的对象(100 个属性),此答案的性能提高了 3 倍。较大的对象(10 万个属性)差异下降到 2 倍。
2021-04-11 05:42:59

从流中选择一个随机元素

function pickRandomProperty(obj) {
    var result;
    var count = 0;
    for (var prop in obj)
        if (Math.random() < 1/++count)
           result = prop;
    return result;
}
一些更正:此功能可以选择第一个属性。在第一次迭代中,count 上的前缀增量使等式右侧的计算结果为 1/1 == 1。由于 Math.random 始终在 [0,1) 范围内(从 0 到 1,不包括 1),表达式的计算结果为 true 并选择了第一个属性。就随机选择的分布而言,它是均匀的。对于一处房产,它有 100% 的机会被选中。如果有两个,则有 50% 的几率会被选中。与三个一个 33.3%。等等。此解决方案具有最小的内存占用。
2021-03-13 05:42:59
这似乎偏向于对象中的第一个元素。我还没想明白为什么!
2021-03-24 05:42:59
这永远不会选择第一个属性(Math.random 总是 < 1),之后每个数字将有 0.5 次被选中的机会。因此,第二个属性为 0.5,第三个属性为 0.25,第四个属性为 0.125,以此类推。
2021-03-28 05:42:59
ECMAScript 标准是否说明了总是以相同顺序遍历的属性?大多数实现中的对象具有稳定的排序,但规范中未定义行为:stackoverflow.com/questions/280713/...
2021-03-29 05:42:59
@davidhadas 考虑三个元素的序列。第一个被选中的概率为 1。但是,它可能会被第二个元素替换(注意我们不会立即返回!),概率为 1/2。第二个元素又可能被第三个元素替换,概率为 1/3。所以我们得到 P(first) = P(first pick) * P(第二个没有被选中) * P(第三个没有被选中) = 1 * 1/2 * 2/3 = 1/3; P(第二个) = P(第二个选择) * P(第三个未选择) = 1/2 * 1/3 = 1/3; P(第三个) = P(第三个选择) = 1/3。
2021-04-08 05:42:59

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

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

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。很好的答案,值得更多赞!只是让一切变得更容易理解!
2021-03-31 05:42:59

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

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

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

在您的情况下,请继续使用:

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

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

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

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

return keys[keys.length * Math.random() << 0];
Dang << 比使用 Math.floor() 优雅得多,也可能更便宜。我真的必须静下心来学习如何使用这些按位运算符。
2021-03-16 05:42:59
在这种情况下,按位运算符的使用更可能是一种黑客行为,因为它需要一个整数作为输入,它会转换数字。应用于<< 0整数将什么也不做。parseInt()会做同样的工作。所以除了编写不太容易理解的代码之外,这里没有什么可学的。
2021-03-29 05:42:59
Object.keys 在这里很有用 var keys = Object.keys(obj)
2021-04-01 05:42:59