Chọn thuộc tính ngẫu nhiên từ một đối tượng Javascript


89

Giả sử bạn có một đối tượng Javascript như {'cat': 'meo', 'dog': 'woof' ...} Có cách nào ngắn gọn hơn để chọn một thuộc tính ngẫu nhiên từ đối tượng hơn là cách dài dòng mà tôi đã nghĩ ra không :

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, vui lòng chọn lại câu trả lời đã chọn của bạn ... @kennytm đã trả lời đúng trước những người khác. Câu trả lời của David chỉ đơn giản là xấu mã hóa (mặc dù nó hoạt động)
vsync

Lưu ý rằng câu hỏi và câu trả lời thực sự tìm kiếm việc trả về giá trị của thuộc tính đối tượng ngẫu nhiên, không phải thuộc tính ngẫu nhiên như tiêu đề câu hỏi sẽ gợi ý.
kontur

Câu trả lời:


182

Câu trả lời đã chọn sẽ hoạt động tốt. Tuy nhiên, câu trả lời này sẽ chạy nhanh hơn:

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

3
này là tốt hơn vì nó không sử dụng một vòng lặp
Dominic

14
Tôi đã thực hiện một số thử nghiệm và có vẻ như câu trả lời đã chọn hoạt động tốt và lựa chọn tài sản là không thiên vị (trái với suy đoán giữa các câu trả lời); tuy nhiên, tôi đã thử nghiệm trên một đối tượng với 170.000 khóa và giải pháp ở đây nhanh hơn gấp đôi so với giải pháp đã chọn.
Dragonfly

8
<< 0 (bithift sang trái bằng 0) có phải là một phương thức viết tắt của Math.round () không?
SystemicPlural

4
This jsperf jsperf.com/random-object-property-selection đánh giá câu trả lời này và câu trả lời đã chọn. Câu trả lời này hoạt động tốt hơn 3x đối với các đối tượng nhỏ hơn (100 thuộc tính). Các đối tượng lớn hơn (100k thuộc tính), sự khác biệt giảm xuống 2 lần tốt hơn.
Constablebrew

2
@MuhammadUmer - Không. Trả Math.random()về một số trong phạm vi [0,1).
Yay295 12/12/15

74

Chọn một phần tử ngẫu nhiên từ một luồng

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

2
Tiêu chuẩn ECMAScript có nói gì về các thuộc tính luôn được duyệt theo cùng một thứ tự không? Các đối tượng trong hầu hết các trường có trật tự ổn định, nhưng hành vi là undefined trong spec: stackoverflow.com/questions/280713/...
Brendan Berg

4
Điều này dường như có sự nghiêng về phần tử đầu tiên trong đối tượng. Tôi vẫn chưa tìm ra lý do tại sao!
Cole Gleason

7
Điều này sẽ không bao giờ chọn thuộc tính đầu tiên (Math.random luôn <1) và sau đó mỗi số sẽ có 0,5 cơ hội được chọn. Vì vậy, 0,5 cho các tài sản thứ hai, 0.25 cho 3, 0,125 cho 4th, vv
SystemicPlural

4
Một số chỉnh sửa: Chức năng này có thể chọn thuộc tính đầu tiên. Trong lần lặp đầu tiên, gia số tiền tố về số đếm làm cho vế phải của phương trình được đánh giá là 1/1 == 1. Vì Math.random luôn nằm trong phạm vi [0,1) (không đến một, không bao gồm một), biểu thức đánh giá là true và thuộc tính đầu tiên được chọn. Theo như sự phân bố của lựa chọn ngẫu nhiên, nó là đồng nhất. Với một tài sản, có 100% khả năng nó sẽ được chọn. Với hai, có 50% khả năng một trong hai sẽ được chọn. Với ba là 33,3%. Và như thế. Giải pháp này có bộ nhớ tối thiểu.
Constablebrew

3
@davidhadas Hãy xem xét một chuỗi gồm ba phần tử. Phần tử đầu tiên được chọn với xác suất là 1. Tuy nhiên, phần tử thứ hai có thể bị thay thế (lưu ý rằng chúng tôi không quay lại ngay lập tức!) Bằng phần tử thứ hai với xác suất 1/2. Phần tử thứ hai có thể lần lượt được thay thế bằng phần tử thứ ba, với xác suất là 1/3. Vì vậy, chúng ta nhận được P (đầu tiên) = P (đầu tiên được chọn) * P (thứ hai không được chọn) * P (thứ ba không được chọn) = 1 * 1/2 * 2/3 = 1/3; P (thứ hai) = P (thứ hai được chọn) * P (thứ ba không được chọn) = 1/2 * 1/3 = 1/3; P (thứ ba) = P (thứ ba được chọn) = 1/3.
Martin Törnwall

19

Tôi không nghĩ rằng bất kỳ ví dụ nào đủ khó hiểu, vì vậy đây là một ví dụ thực sự khó đọc để làm điều tương tự.

Chỉnh sửa: Bạn có thể không nên làm điều này trừ khi bạn muốn đồng nghiệp ghét mình.

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

Giải trình:

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

Tay dài, bớt khó hiểu:

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
đây thực sự là giải pháp hợp lý nhất
Paweł

2
Tôi thích điều này nhất, với giải thích và mọi thứ và cũng bao gồm một POJO ví dụ thực tế. Câu trả lời tuyệt vời, xứng đáng nhận được nhiều phiếu bầu hơn! Chỉ làm cho mọi thứ dễ hiểu hơn nhiều!
Tigerrrrr

1
Giải pháp tốt nhất! Điều này nên được bình chọn nhiều nhất.
nilsoviani

15

Bạn có thể vừa tạo một dãy phím vừa đi qua đối tượng.

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

Sau đó, chọn ngẫu nhiên một phần tử từ các phím:

return keys[keys.length * Math.random() << 0];

13
Object.keys là hữu ích ở đâyvar keys = Object.keys(obj)
whadar

Dang << duyên dáng hơn rất nhiều so với sử dụng Math.floor (), có lẽ cũng ít tốn kém hơn. Tôi thực sự phải xuống và học cách sử dụng các toán tử bitwise đó.
Paul J

5
Trong trường hợp này, việc sử dụng toán tử bitwise có nhiều khả năng là một vụ hack, bởi vì nó cần một số nguyên làm đầu vào, nó sẽ chuyển đổi số. Áp dụng << 0cho một số nguyên sẽ không làm gì cả. parseInt()sẽ làm công việc tương tự. Vì vậy, không có gì để học ở đây ngoại trừ việc viết mã ít dễ hiểu hơn.
hạ cánh

13

Nếu bạn có khả năng sử dụng các thư viện, bạn có thể thấy rằng thư viện Lo-Dash JS có rất nhiều phương pháp rất hữu ích cho những trường hợp như vậy. Trong trường hợp này, hãy tiếp tục và kiểm tra _.sample().

(Lưu ý rằng quy ước Lo-Dash đang đặt tên cho đối tượng thư viện _. Đừng quên kiểm tra cài đặt trong cùng một trang để thiết lập nó cho dự án của bạn.)

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

Trong trường hợp của bạn, hãy tiếp tục và sử dụng:

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

3

Nếu bạn đang sử dụng underscore.js, bạn có thể làm:

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

Thêm:

Nếu bạn cần nhiều thuộc tính ngẫu nhiên, hãy thêm một số:

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

Nếu bạn cần một đối tượng mới chỉ có các thuộc tính ngẫu nhiên đó:

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

0

Một cách đơn giản khác để làm điều này là xác định một hàm áp dụng Math.random()hàm.

Hàm này trả về một số nguyên ngẫu nhiên nằm trong khoảng từ 'min'

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

Sau đó, trích xuất 'khóa' hoặc 'giá trị' hoặc 'cả hai' từ đối tượng Javascript của bạn mỗi khi bạn cung cấp hàm trên dưới dạng tham số.

var randNum = getRandomArbitrary(0, 7);
var index = randNum;
return Object.key(index); // Returns a random key
return Object.values(index); //Returns the corresponding value.

Ý của bạn là Object.values ​​(someObject) [chỉ mục]?
Bemmu

Biến chỉ mục mà tôi đã sử dụng để lưu trữ số ngẫu nhiên được tạo chỉ là một vùng chứa, không có gì đặc biệt. Nếu tôi không lưu trữ số được tạo vào một biến khác thì mỗi phiên bản của hàm getRandomArbitrarysẽ tạo ra một số ngẫu nhiên mới mỗi khi nó được gọi.
Sushant Chaudhary

0

Trong một đối tượng JSON, bạn phải đặt cái này:

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

Hàm đó sẽ trả về phần bên trong của một thuộc tính ngẫu nhiên.


0

Bạn có thể sử dụng mã sau để chọn một thuộc tính ngẫu nhiên từ một đối tượng 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

Mặc dù mã này có thể trả lời câu hỏi, nhưng việc cung cấp ngữ cảnh bổ sung về cách thức và / hoặc lý do tại sao nó giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Nic3500
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.