Wählen Sie eine zufällige Eigenschaft aus einem Javascript-Objekt aus

88

Angenommen, Sie haben ein Javascript-Objekt wie {'cat': 'meow', 'dog': 'woof' ...}. Gibt es eine präzisere Möglichkeit, eine zufällige Eigenschaft aus dem Objekt auszuwählen, als diese langwierige Methode, die ich mir ausgedacht habe? ::

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
quelle
OP, bitte wählen Sie Ihre ausgewählte Antwort erneut aus ... @kennytm hat sie vor anderen richtig beantwortet. Davids Antwort ist einfach schlechte Codierung (obwohl es funktioniert)
vsync

Antworten:

178

Die gewählte Antwort wird gut funktionieren. Diese Antwort wird jedoch schneller ausgeführt:

var randomProperty = function (obj) {
    var keys = Object.keys(obj);
    return obj[keys[ keys.length * Math.random() << 0]];
};
Lawrence Whiteside
quelle
3
Dies ist besser, da es keine Schleife verwendet
Dominic
13
Ich habe einige Tests durchgeführt, und es scheint, dass die gewählte Antwort gut funktioniert und dass die Wahl des Eigentums unvoreingenommen ist (im Gegensatz zu Spekulationen unter den Antworten); Ich habe jedoch ein Objekt mit 170.000 Schlüsseln getestet und die Lösung war hier etwa doppelt so schnell wie die ausgewählte Lösung.
Libelle
8
Ist << 0 (Bitverschiebung um 0 nach links) eine Kurzmethode zum Schreiben von Math.round ()?
SystemicPlural
4
Diese jsperf jsperf.com/random-object-property-selection vergleicht diese Antwort und die ausgewählte Antwort. Diese Antwort ist bei kleineren Objekten (100 Eigenschaften) um das Dreifache besser. Bei größeren Objekten (100.000 Eigenschaften) sinkt der Unterschied auf das Zweifache.
Constablebrew
2
@MuhammadUmer - Nr. Gibt Math.random()eine Zahl im Bereich [0,1] zurück.
Yay295
74

Auswählen eines zufälligen Elements aus einem Stream

function pickRandomProperty(obj) {
    var result;
    var count = 0;
    for (var prop in obj)
        if (Math.random() < 1/++count)
           result = prop;
    return result;
}
David Leonard
quelle
2
Sagt der ECMAScript-Standard etwas über die Eigenschaften aus, die immer in derselben Reihenfolge durchlaufen werden? Objekte in den meisten Implementierungen haben eine stabile Reihenfolge, aber das Verhalten ist in der Spezifikation undefiniert: stackoverflow.com/questions/280713/…
Brendan Berg
4
Dies scheint einen Versatz zum ersten Element im Objekt zu haben. Ich habe noch nicht herausgefunden warum!
Cole Gleason
7
Dadurch wird niemals die erste Eigenschaft ausgewählt (Math.random ist immer <1), und danach hat jede Zahl eine Chance von 0,5, ausgewählt zu werden. Also 0,5 für die zweite Eigenschaft, 0,25 für die 3., 0,125 für die 4. usw.
SystemicPlural
4
Einige Korrekturen: Diese Funktion kann die erste Eigenschaft auswählen. Bei der ersten Iteration bewirkt das Präfixinkrement bei der Zählung, dass die rechte Seite der Gleichung mit 1/1 == 1 bewertet wird. Da Math.random immer im Bereich [0,1) liegt (null bis eins, ohne eins), Der Ausdruck wird als wahr ausgewertet und die erste Eigenschaft wird ausgewählt. Die Verteilung der Zufallsauswahl ist einheitlich. Bei einer Eigenschaft besteht eine 100% ige Chance, dass sie ausgewählt wird. Bei zwei besteht eine 50% ige Chance, dass einer von beiden ausgewählt wird. Mit drei 33,3%. Und so weiter. Diese Lösung hat einen minimalen Speicherbedarf.
Constablebrew
3
@davidhadas Betrachten Sie eine Folge von drei Elementen. Das erste Element wird mit einer Wahrscheinlichkeit von 1 ausgewählt. Es kann jedoch durch das zweite Element mit einer Wahrscheinlichkeit von 1/2 ersetzt werden (beachten Sie, dass wir nicht sofort zurückkehren!). Das zweite Element könnte wiederum mit einer Wahrscheinlichkeit von 1/3 durch das dritte Element ersetzt werden. Wir erhalten also P (erste) = P (erste Auswahl) * P (zweite nicht ausgewählt) * P (dritte nicht ausgewählt) = 1 * 1/2 * 2/3 = 1/3; P (zweite) = P (zweite ausgewählt) * P (dritte nicht ausgewählt) = 1/2 * 1/3 = 1/3; P (dritter) = P (dritter ausgewählt) = 1/3.
Martin Törnwall
16

Ich fand keines der Beispiele verwirrend genug, daher ist hier ein wirklich schwer zu lesendes Beispiel, das dasselbe tut.

Bearbeiten: Sie sollten dies wahrscheinlich nicht tun, es sei denn, Sie möchten, dass Ihre Mitarbeiter Sie hassen.

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

Erläuterung:

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

Lange Hand, weniger verwirrend:

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.
quelle
2
Dies ist eigentlich die vernünftigste Lösung
Paweł
1
Ich mag das am meisten, mit Erklärungen und allem und enthält auch ein aktuelles Beispiel POJO. Tolle Antworten, verdient mehr Upvotes! Macht einfach alles so viel einfacher zu verstehen!
Tigerrrrr
15

Sie können einfach eine Reihe von Schlüsseln erstellen, während Sie durch das Objekt gehen.

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

Wählen Sie dann zufällig ein Element aus den Tasten aus:

return keys[keys.length * Math.random() << 0];
kennytm
quelle
13
Object.keys ist hier nützlichvar keys = Object.keys(obj)
whadar
Dang << ist so viel eleganter als Math.floor (), wahrscheinlich auch billiger. Ich muss wirklich runter und lernen, wie man diese bitweisen Operatoren benutzt.
Paul J
5
In diesem Fall ist die Verwendung des bitweisen Operators eher ein Hack, da er eine Ganzzahl als Eingabe benötigt und die Zahl konvertiert. Das Anwenden << 0auf eine Ganzzahl führt zu nichts. parseInt()wird den gleichen Job machen. Hier gibt es also nichts zu lernen, außer weniger verständlichen Code zu schreiben.
Landunder
13

Wenn Sie in der Lage sind, Bibliotheken zu verwenden, finden Sie möglicherweise, dass die Lo-Dash JS-Bibliothek viele sehr nützliche Methoden für solche Fälle bietet. In diesem Fall überprüfen Sie dies _.sample().

(Hinweis Die Lo-Dash-Konvention benennt das Bibliotheksobjekt _. Vergessen Sie nicht, die Installation auf derselben Seite zu überprüfen, um es für Ihr Projekt einzurichten.)

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

In Ihrem Fall verwenden Sie:

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

Wenn Sie underscore.js verwenden , können Sie Folgendes tun:

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

Extra:

Wenn Sie mehrere zufällige Eigenschaften benötigen, fügen Sie eine Zahl hinzu:

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

Wenn Sie ein neues Objekt mit nur diesen zufälligen Eigenschaften benötigen:

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

Eine andere einfache Möglichkeit, dies zu tun, wäre das Definieren einer Funktion, die eine Funktion anwendet Math.random().

Diese Funktion gibt eine zufällige Ganzzahl zurück, die von 'min' reicht.

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

Extrahieren Sie dann jedes Mal, wenn Sie die obige Funktion als Parameter angeben, entweder einen 'Schlüssel' oder einen 'Wert' oder 'beides' aus Ihrem Javascript-Objekt.

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
quelle
Meinen Sie Object.values ​​(someObject) [index]?
Bemmu
Die Indexvariable , mit der ich die generierte Zufallszahl gespeichert habe, ist nur ein Container, nichts Besonderes. Hätte ich die generierte Nummer nicht in einer anderen Variablen gespeichert, getRandomArbitrarywürde jede Instanz der Funktion bei jedem Aufruf eine neue Zufallszahl generieren.
Sushant Chaudhary
0

In einem JSON-Objekt müssen Sie Folgendes platzieren:

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

Diese Funktion gibt das Innere einer zufälligen Eigenschaft zurück.

Sybsuper
quelle
0

Mit dem folgenden Code können Sie eine zufällige Eigenschaft aus einem JavaScript-Objekt auswählen:

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
quelle
Während dieser Code die Frage möglicherweise beantwortet, würde die Bereitstellung eines zusätzlichen Kontexts darüber, wie und / oder warum das Problem gelöst wird, den langfristigen Wert der Antwort verbessern.
Nic3500