Выбрать случайное свойство из объекта Javascript

89

Предположим, у вас есть объект 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;
        }
    }       
}
Бемму
источник
OP, пожалуйста, повторно выберите выбранный ответ ... @kennytm ответил на него правильно раньше других. Ответ Дэвида - просто плохое кодирование (хотя он работает)
vsync
Обратите внимание, что вопрос и ответы на самом деле ищут возвращение значения случайного свойства объекта, а не случайного свойства, как следует из названия вопроса.
Контур

Ответы:

182

Выбранный ответ подойдет. Однако этот ответ будет работать быстрее:

var randomProperty = function (obj) {
    var keys = Object.keys(obj);
    return obj[keys[ keys.length * Math.random() << 0]];
};
Лоуренс Уайтсайд
источник
3
это лучше, так как в нем не используется петля
Доминик
14
Я провел некоторое тестирование, и оказалось, что выбранный ответ работает нормально и что выбор свойства является беспристрастным (вопреки предположениям среди ответов); однако я тестировал объект с 170 000 ключей, и решение здесь было примерно в два раза быстрее, чем выбранное решение.
Dragonfly
8
<< 0 (сдвиг влево на 0) сокращенный метод записи Math.round ()?
SystemicPlural
4
Этот jsperf jsperf.com/random-object-property-selection сравнивает этот ответ и выбранный ответ. Этот ответ работает в 3 раза лучше для небольших объектов (100 свойств). Для больших объектов (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 для 4-го и т. Д.
SystemicPlural
4
Некоторые исправления: Эта функция может выбирать первое свойство. На первой итерации приращение префикса по счетчику приводит к тому, что правая часть уравнения оценивается как 1/1 == 1. Поскольку Math.random всегда находится в диапазоне [0,1) (от нуля до единицы, за исключением единицы), выражение истинно, и выбирается первое свойство. Что касается распределения случайного выбора, то оно равномерное. Для одного свойства есть 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.
Мартин Торнуолл 01
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];
Kennytm
источник
13
Здесь пригодится var keys = Object.keys(obj)
Object.keys
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 02
Индекс переменной , которую я использовал для хранения сгенерированного случайного числа просто контейнер, ничего особенного. Если бы я не сохранил сгенерированное число в другой переменной, тогда каждый экземпляр функции getRandomArbitraryгенерировал бы новое случайное число при каждом вызове.
Sushant Chaudhary 02
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;
  }
}

Эта функция вернет внутреннюю часть случайного свойства.

Sybsuper
источник
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 05