2012-06-27 7 views
8

Ich bin mir nicht sicher, wie NSSet anyObject arbeiten. Was bedeutet es, dass "das zurückgegebene Objekt zur Bequemlichkeit des Sets gewählt wird" (aus der NSSet class reference)?NSSet wie man Objekt zufällig extrahiert?

Weiter, wie kann ich am besten Objekte zufällig aus einem NSSet extrahieren? Ich dachte über allObjects in einem Array und dann myArray[arc4random_uniform(x)] wo x ist die Anzahl der Objekte im Array.

+0

Sind Sie mit Wiederholungen ok? – Richard

+0

Ziemlich neugierig auf mich selbst, ich denke, Sie könnten anyObject eine zufällige Anzahl von Malen, aber Ihre Array-Lösung klingt besser. – Patrick

+0

Ich denke, das Konvertieren von NSArray zu NSSet hin und her ist keine gute Möglichkeit zum Mischen. –

Antwort

13

Normalerweise werden NSSet Instanzen mit einem CFHash Backing erstellt, so dass sie fast immer das erste Objekt in diesem Hash zurückgeben, da es am schnellsten zu suchen ist. Der Grund dafür lautet

Das zurückgegebene Objekt wird bei der Verwendung des Sets ausgewählt - die Auswahl ist nicht garantiert zufällig.

Da Sie nicht immer wissen, wird es eine Backing-Array haben. Für alles, was Sie wissen, hat die NSSet Instanz, die Sie haben, eine NSDictionary Unterstützung, oder eine andere ähnliche Datenstruktur.

Also abschließend, wenn Sie ein zufälliges Objekt von einem benötigen, verwenden Sie nicht -anyObject, sondern allObjects: und dann mischen Sie das Array.

+0

Ja! Ich denke, das versetzt mich in die Rep-Kappe für heute! –

+0

Jetzt können Sie schlafen gehen :) – Anne

+0

@Anne Nö, jetzt ist es Zeit, es auf Meta zu tun! –

4

Die Dokumentation liest, dass anyObject kehrt

Eines der Objekte in der Menge, oder null, wenn die Menge keine Objekte enthält. Das zurückgegebene Objekt wird nach Belieben ausgewählt. Die Auswahl ist nicht garantiert zufällig.

Höchstwahrscheinlich gibt es einen deterministischen Algorithmus bei der Arbeit.

Die zuverlässigste Sache zu tun wäre, wie Sie schlagen ein NSArray mit der NSSet Methode allObjects, und wählen Sie dann ein Zufallselement aus, dass mit arc4random() % N zu schaffen, wo N die count der NSArray ist.

+4

Besser arc4random_uniform verwenden statt nur den Modulo-Operator, wie Fabio in seiner Frage vorgeschlagen hat, um Modulo-Bias zu vermeiden. – Sven

14

Zitat von NSSet Class Reference:

Das zurückgegebene Objekt in der Bequemlichkeit-die Auswahl des Satzes gewählt wird, wird nicht als zufällig garantiert.

Für "Zufälligkeit", wandeln die NSSet zu einem NSArray[theSet allObjects] verwenden.
Wählen Sie als nächstes ein beliebiges Objekt mit arc4random_uniform() aus.

+2

Lässt sich fair hier sein, müssen Sie auch den Randomizer unterschiedlich jedes Startup für sie wirklich zufällig zu initialisieren, und selbst dann ist es pseudozufällig :-) +1 – trumpetlicks

1

Ich benutze arc4random() und zwei veränderbare Arrays einen zufälligen und einzigartigen Satz von Objekten zu erhalten:

NSMutableArray *selectionPool = ...; 

int numberOfObjectsToSelect = x; 

NSMutableArray *selectedObjects = [[NSMutableArray alloc] initWithCapacity:numberOfObjectsToSelect]; 

int modulus = selectionPool.count - 1; 

for (int i = 0; i < numberOfObjectsToSelect; i++) { 

    int j = arc4random() % (modulus--); 
    [selectedObjects addObject:[selectionPool objectAtIndex:j]]; 
    [selectionPool removeObjectAtIndex:j]; 

} 

Ich bin nicht sicher, wie effizient es für große Sammlungen sein würde, aber es ist für mich gearbeitet mit Sammlungen, die in den unteren 100 von Objekten nummerieren.

+0

würde Division durch Null Ausnahme erhalten, wenn 'numberOfObjectsToSelect == selectionPool.count' –