从Javascript对象中选择随机属性

Bem*_*mmu 77 javascript

假设你有一个Javascript对象,如{'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;
        }
    }       
}
Run Code Online (Sandbox Code Playgroud)

小智 151

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

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

  • 我做了一些测试,似乎选择的答案工作正常,财产的选择是公正的(与答复中的推测相反); 但是,我测试了一个带有170,000个按键的对象,这里的解决方案速度大约是所选解决方案的两倍. (12认同)
  • 写入Math.round()的简写方法是<< 0(向左移位0) (8认同)
  • 请解释为什么您认为所选答案不起作用. (4认同)
  • 这个jsperf http://jsperf.com/random-object-property-selection对这个答案和所选答案进行了基准测试.对于较小的对象(100个属性),此答案的性能提高3倍.较大的物体(100k属性)差异降至2倍更好. (4认同)
  • 这是更好的,因为它不使用循环 (3认同)
  • @MuhammadUmer - No.`Math.random()`返回[0,1]范围内的数字. (2认同)
  • @SystemicPlural 它更像是`parseInt(keys.length * Math.random(), 0)`的简写 (2认同)

Dav*_*ard 74

从流中挑选一个随机元素

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

  • 这将永远不会选择第一个属性(Math.random总是<1),之后每个数字将有0.5的机会被选中.因此第二个属性为0.5,第三个属性为0.25,第四个属性为0.125等. (5认同)
  • 这似乎与对象中的第一个元素有偏差.我还没弄明白为什么呢! (4认同)
  • 一些更正:此功能可以选择第一个属性.在第一次迭代中,计数的前缀增量使得等式的右侧评估为1/1 == 1.由于Math.random总是在[0,1)范围内(零到一,不包括一个),表达式求值为true,并选择第一个属性.就随机选择的分布而言,它是均匀的.拥有一处房产将有100%的可能性被选中.有两个,将有50%的机会被选中.三个人占33.3%.等等.该解决方案具有最小的内存占用. (4认同)
  • @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. (3认同)
  • ECMAScript标准是否总是以相同的顺序说明有关属性的任何内容?大多数实现中的对象具有稳定的排序,但规范中的行为未定义:http://stackoverflow.com/questions/280713/elements-order-for-in-loop-in-javascript/280861#280861 (2认同)

ken*_*ytm 15

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

var keys = [];
for (var prop in obj) {
    if (obj.hasOwnProperty(prop)) {
        keys.push(prop);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

return keys[keys.length * Math.random() << 0];
Run Code Online (Sandbox Code Playgroud)

  • Object.keys在这里很有用`var keys = Object.keys(obj)` (13认同)
  • 在这种情况下,按位运算符的使用更可能是hack,因为它需要一个整数作为输入,它会转换数字.将"<< 0"应用于整数将不起作用.`parseInt()`将完成同样的工作.所以除了编写不易理解的代码之外,没有什么可学的. (3认同)

Pau*_*l J 14

我没想到任何一个例子都让人感到困惑,所以这里有一个很难读的例子做同样的事情.

编辑:你可能不应该这样做,除非你希望你的同事恨你.

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)]]);
Run Code Online (Sandbox Code Playgroud)

说明:

// 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)]]
Run Code Online (Sandbox Code Playgroud)

长手,不那么困惑:

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]; 
Run Code Online (Sandbox Code Playgroud)

  • 这实际上是最合理的解决方案 (2认同)
  • 我最喜欢这个,有解释和一切,还包括一个实际的 POJO 示例。很好的答案,值得更多的赞!只是让一切变得更容易理解! (2认同)

Sel*_*ish 12

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

(注意Lo-Dash约定是命名库对象_.不要忘记在同一页面中检查安装以为项目设置它.)

_.sample([1, 2, 3, 4]);
// ? 2
Run Code Online (Sandbox Code Playgroud)

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

_.sample({
    cat: 'meow',
    dog: 'woof',
    mouse: 'squeak'
});
// ? "woof"
Run Code Online (Sandbox Code Playgroud)


Nel*_*elu 6

如果你使用underscore.js你可以这样做:

_.sample(Object.keys(animals));
Run Code Online (Sandbox Code Playgroud)

额外的:

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

_.sample(Object.keys(animals), 3);
Run Code Online (Sandbox Code Playgroud)

如果您需要一个仅具有这些随机属性的新对象:

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