Pilih properti acak dari objek Javascript

89

Misalkan Anda memiliki objek Javascript seperti {'cat': 'meow', 'dog': 'woof' ...} Apakah ada cara yang lebih ringkas untuk memilih properti acak dari objek daripada cara bertele-tele yang saya buat ini :

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;
        }
    }       
}
Bemmu
sumber
OP, pilih ulang jawaban yang Anda pilih ... @kennytm menjawabnya dengan benar sebelum yang lain. Jawaban David hanyalah pengkodean yang buruk (meskipun berhasil)
vsync
Perhatikan bahwa pertanyaan dan jawaban sebenarnya mencari mengembalikan nilai properti objek acak, bukan properti acak seperti yang disarankan oleh judul pertanyaan.
kontur

Jawaban:

182

Jawaban yang dipilih akan bekerja dengan baik. Namun, jawaban ini akan berjalan lebih cepat:

var randomProperty = function (obj) {
    var keys = Object.keys(obj);
    return obj[keys[ keys.length * Math.random() << 0]];
};
Lawrence Whiteside
sumber
3
ini lebih baik karena tidak menggunakan loop
Dominic
14
Saya melakukan beberapa pengujian, dan tampaknya jawaban yang dipilih berfungsi dengan baik dan bahwa pilihan properti tidak bias (bertentangan dengan spekulasi di antara tanggapan); namun, saya menguji objek dengan 170.000 kunci dan solusi di sini sekitar dua kali lebih cepat dari solusi yang dipilih.
Dragonfly
8
Apakah << 0 (bitshift to the left by 0) merupakan metode penulisan cepat Math.round ()?
SystemicPlural
4
Jsperf jsperf.com/random-object-property-selection ini menandai jawaban ini dan jawaban yang dipilih. Jawaban ini berkinerja lebih baik sebanyak 3x untuk objek yang lebih kecil (100 properti). Objek yang lebih besar (properti 100k) perbedaannya turun menjadi 2x lebih baik.
Constablebrew
2
@MuhammadUmer - Tidak. Math.random()Mengembalikan angka dalam kisaran [0,1).
Yay295
74

Memilih elemen acak dari aliran

function pickRandomProperty(obj) {
    var result;
    var count = 0;
    for (var prop in obj)
        if (Math.random() < 1/++count)
           result = prop;
    return result;
}
David Leonard
sumber
2
Apakah standar ECMAScript menyatakan sesuatu tentang properti yang selalu dilintasi dalam urutan yang sama? Objek di sebagian besar implementasi memiliki pengurutan yang stabil, tetapi perilakunya tidak ditentukan dalam spesifikasi: stackoverflow.com/questions/280713/…
Brendan Berg
4
Ini tampaknya memiliki kemiringan terhadap elemen pertama pada objek. Saya belum tahu kenapa!
Cole Gleason
7
Ini tidak akan pernah memilih properti pertama (Math.random selalu <1) dan setelah itu setiap nomor akan memiliki peluang 0,5 untuk dipilih. Jadi 0,5 untuk properti kedua, 0,25 untuk yang ke-3, 0,125 untuk yang ke-4, dll.
SystemicPlural
4
Beberapa koreksi: Fungsi ini dapat memilih properti pertama. Pada iterasi pertama, kenaikan prefiks pada hitungan membuat ruas kanan persamaan bernilai 1/1 == 1. Karena Math.random selalu dalam kisaran [0,1) (nol hingga satu, tidak termasuk satu), ekspresi bernilai true dan properti pertama dipilih. Sejauh distribusi seleksi acak berjalan, itu seragam. Dengan satu properti, ada kemungkinan 100% itu akan dipilih. Dengan dua, ada kemungkinan 50% keduanya akan dipilih. Dengan tiga a 33,3%. Dan seterusnya. Solusi ini memiliki jejak memori yang minimal.
Constablebrew
3
@davidhadas Pertimbangkan urutan tiga elemen. Yang pertama diambil dengan probabilitas 1. Namun, itu mungkin diganti (perhatikan bahwa kami tidak segera kembali!) Oleh elemen kedua dengan probabilitas 1/2. Elemen kedua mungkin akan digantikan oleh elemen ketiga, dengan probabilitas 1/3. Jadi kita mendapatkan P (pertama) = P (pertama dipetik) * P (kedua tidak dipetik) * P (ketiga tidak dipilih) = 1 * 1/2 * 2/3 = 1/3; P (kedua) = P (kedua dipilih) * P (ketiga tidak dipilih) = 1/2 * 1/3 = 1/3; P (ketiga) = P (ketiga dipilih) = 1/3.
Martin Törnwall
19

Saya rasa tidak ada contoh yang cukup membingungkan, jadi inilah contoh yang sangat sulit dibaca dengan melakukan hal yang sama.

Sunting: Anda mungkin tidak boleh melakukan ini kecuali Anda ingin rekan kerja Anda membenci Anda.

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

Penjelasan:

// 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)]]

Tangan panjang, tidak terlalu membingungkan:

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]; 
Paul J.
sumber
4
ini sebenarnya adalah solusi yang paling masuk akal
Paweł
2
Saya paling suka ini, dengan penjelasan dan semuanya dan juga menyertakan contoh POJO yang sebenarnya. Jawaban Hebat, layak mendapatkan lebih banyak suara positif! Hanya membuat segalanya jadi lebih mudah untuk dipahami!
Tigerrrrr
1
Solusi terbaik! Ini harus paling banyak dipilih.
nilsoviani
15

Anda bisa membuat array kunci sambil berjalan melalui objek.

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

Kemudian, pilih elemen secara acak dari kunci:

return keys[keys.length * Math.random() << 0];
kennytm
sumber
13
Object.keys berguna di sinivar keys = Object.keys(obj)
whadar
Dang << jauh lebih anggun daripada menggunakan Math.floor (), mungkin lebih murah juga. Saya benar-benar harus turun dan belajar cara menggunakan operator bitwise tersebut.
Paul J
5
Dalam hal ini penggunaan operator bitwise lebih cenderung diretas, karena membutuhkan bilangan bulat sebagai input, itu mengubah nomor tersebut. Menerapkan << 0ke integer tidak akan melakukan apa-apa. parseInt()akan melakukan pekerjaan yang sama. Jadi tidak ada yang bisa dipelajari di sini kecuali menulis kode yang kurang bisa dimengerti.
mendarat di bawah
13

Jika Anda mampu menggunakan perpustakaan, Anda mungkin menemukan bahwa perpustakaan JS Lo-Dash memiliki banyak metode yang sangat berguna untuk kasus seperti itu. Dalam hal ini, lanjutkan dan periksa_.sample() .

(Catatan Konvensi Lo-Dash menamai objek perpustakaan _. Jangan lupa untuk memeriksa penginstalan di halaman yang sama untuk menyiapkannya untuk proyek Anda.)

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

Dalam kasus Anda, lanjutkan dan gunakan:

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

Jika Anda menggunakan underscore.js, Anda dapat melakukan:

_.sample(Object.keys(animals));

Tambahan:

Jika Anda membutuhkan beberapa properti acak, tambahkan nomor:

_.sample(Object.keys(animals), 3);

Jika Anda membutuhkan objek baru dengan hanya properti acak tersebut:

const props = _.sample(Object.keys(animals), 3);
const newObject = _.pick(animals, (val, key) => props.indexOf(key) > -1);
Nelu
sumber
0

Cara sederhana lainnya untuk melakukan ini adalah dengan mendefinisikan fungsi yang menerapkan Math.random()fungsi.

Fungsi ini mengembalikan integer acak yang berkisar dari 'min'

function getRandomArbitrary(min, max) {
  return Math.floor(Math.random() * (max - min) + min);
}

Kemudian, ekstrak 'kunci' atau 'nilai' atau 'keduanya' dari objek Javascript setiap kali Anda memberikan fungsi di atas sebagai parameter.

var randNum = getRandomArbitrary(0, 7);
var index = randNum;
return Object.key(index); // Returns a random key
return Object.values(index); //Returns the corresponding value.
Sushant Chaudhary
sumber
Apakah yang Anda maksud Object.values ​​(someObject) [index]?
Bemmu
The Indeks variabel yang saya digunakan untuk menyimpan dihasilkan acak nomor hanyalah sebuah wadah, tidak ada yang istimewa. Seandainya saya tidak menyimpan nomor yang dihasilkan ke variabel lain, maka setiap instance fungsi getRandomArbitraryakan menghasilkan nomor acak baru setiap kali dipanggil.
Sushant Chaudhary
0

Dalam objek JSON Anda harus menempatkan ini:

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

Fungsi itu akan mengembalikan bagian dalam properti acak.

Sybsuper
sumber
0

Anda dapat menggunakan kode berikut untuk memilih properti acak dari objek 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
Lol Super
sumber
Meskipun kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang bagaimana dan / atau mengapa kode ini memecahkan masalah akan meningkatkan nilai jawaban jangka panjang.
Nic3500