2012-06-27 8 views
8

Non sono sicuro di come funziona il anyObject di NSSet. Cosa significa che "L'oggetto restituito viene scelto a discrezione del set" (dallo NSSet class reference)?NSSet come estrarre l'oggetto casualmente?

Inoltre, come posso estrarre gli oggetti in modo casuale da un NSSet? Stavo pensando di ottenere allObjects in un array e quindi myArray[arc4random_uniform(x)] dove x è il numero di oggetti nell'array.

+0

Stai bene con le ripetizioni? – Richard

+0

Piuttosto curioso di ciò, credo che si possa chiamare anyObject un numero casuale di volte, ma la soluzione dell'array suona meglio. – Patrick

+0

Credo che convertire NSArray in NSSet avanti e indietro non sarà un buon modo di rimescolare. –

risposta

13

Generalmente, le istanze NSSet sono create con un supporto CFHash, quindi restituiscono quasi sempre il primo oggetto in tale hash, poiché è il più veloce da cercare. La ragione per cui dice

L'oggetto restituito viene scelto per comodità del set-la selezione non è garantita per essere casuale.

è perché non sempre si sa che avrà una matrice di supporto. Per quel che ne sai, l'istanza NSSet di cui disponi ha un backup NSDictionary o un'altra struttura di dati simile.

Quindi, in conclusione, se è necessario un oggetto casuale da un NSSet, non utilizzare -anyObject, utilizzare invece allObjects: e quindi rimescolare quell'array.

+0

Sì! Penso che questo mi metta al limite per oggi! –

+0

Ora puoi andare a dormire :) – Anne

+0

@Anne no, ora è il momento di farlo sul meta! –

4

La documentazione si legge che anyObject rendimenti

Uno degli oggetti nel set, o nullo se il set non contiene oggetti. L'oggetto restituito viene scelto per comodità del set: la selezione non è garantita come casuale.

Molto probabilmente c'è un algoritmo deterministico al lavoro.

La cosa più affidabile per fare sarebbe, come lei suggerisce, di creare un NSArray utilizzando il metodo di NSSetallObjects, e quindi scegliere un elemento casuale da quella con cui arc4random() % NN è la count del NSArray.

+4

Meglio usare arc4random_uniform invece semplicemente usando l'operatore modulo, come suggerito da fabio nella sua domanda, per evitare il bias del modulo. – Sven

14

Citazione di NSSet Class Reference:

L'oggetto restituito è scelto presso il set-convenienza la selezione non è garantito per essere casuali.

Per "casualità", convertire il NSSet a un NSArray utilizzando [theSet allObjects].
Quindi, selezionare un oggetto in modo casuale utilizzando arc4random_uniform().

+2

Per essere corretto qui, dovrai anche inizializzare il randomizer in modo diverso per ogni avvio in modo che sia veramente casuale, e anche allora, è pseudocasuale :-) +1 – trumpetlicks

1

Io uso arc4random() e due array mutevoli per ottenere un insieme casuale e unica di oggetti:

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

} 

io non sono sicuro di come efficace sarebbe per grandi collezioni, ma ha funzionato per me con collezioni che si trovano nei bassi 100 degli oggetti.

+0

otterrebbe una divisione con zero exception se 'numberOfObjectsToSelect == selectionPool.count' –

Problemi correlati