Виберіть випадкову властивість з об'єкта Javascript


88

Припустимо, у вас є такий об’єкт 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;
        }
    }       
}

ВП, будь-ласка, переоберіть обрану вами відповідь ... @kennytm правильно відповів на неї перед іншими. Відповідь Девіда - просто погане кодування (хоча це працює)
vsync

Зверніть увагу, що запитання та відповіді насправді шукають повернення значення властивості випадкового об'єкта, а не випадкової властивості, як пропонується в назві запитання.
контур

Відповіді:


181

Обрана відповідь буде добре працювати. Однак ця відповідь буде працювати швидше:

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

3
це краще, оскільки він не використовує петлю
Домінік

13
Я провів тестування, і виявляється, що обрана відповідь працює нормально і що вибір властивості є неупередженим (всупереч припущенням серед відповідей); однак я тестував на об'єкті із 170 000 ключів, і рішення тут було приблизно вдвічі швидше, ніж обране рішення.
Бабка

8
Чи є << 0 (бітове зміщення вліво на 0) скороченим методом написання Math.round ()?
SystemicPlural

4
Цей jsperf jsperf.com/random-object-property-selection тестує цю відповідь та вибрану відповідь. Ця відповідь має кращі результати в 3 рази для менших об’єктів (100 властивостей). У великих об’єктів (властивості 100 тис.) Різниця зменшується вдвічі краще.
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
Здається, це має перекіс до першого елемента об’єкта. Я ще не зрозумів чому!
Cole Gleason

7
Це ніколи не вибере першу властивість (Math.random завжди <1), а після цього кожне число матиме 0,5 шансу бути вибраним. Отже 0,5 для другого властивості, 0,25 для 3-го, 0,125 для 4-го і т.д.
SystemicPlural

4
Деякі виправлення: Ця функція може вибрати першу властивість. На першій ітерації приріст префікса на count робить праву частину рівняння оцінкою до 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.
Martin Tö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)
whadar

Dang << набагато витонченіший, ніж використання Math.floor (), можливо, також дешевший. Мені справді потрібно зійти і навчитися використовувати ці побітові оператори.
Пол Дж.

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) [індекс]?
Бемму,

Індекс змінної , яку я використовував для зберігання згенерованого випадкового числа просто контейнер, нічого особливого. Якби я не зберігав сформоване число в іншій змінній, тоді кожен екземпляр функції 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.