Est-il une manière canonique de générer aléatoirement un tableau en Objective-C?
Réponses
Trop de publicités?Ma bibliothèque utilitaire définit cette catégorie sur NSMutableArray de le faire:
@interface NSMutableArray (ArchUtils_Shuffle)
- (void)shuffle;
@end
// Chooses a random integer below n without bias.
// Computes m, a power of two slightly above n, and takes random() modulo m,
// then throws away the random number if it's between n and m.
// (More naive techniques, like taking random() modulo n, introduce a bias
// towards smaller numbers in the range.)
static NSUInteger random_below(NSUInteger n) {
NSUInteger m = 1;
// Compute smallest power of two greater than n.
// There's probably a faster solution than this loop, but bit-twiddling
// isn't my specialty.
do {
m <<= 1;
} while(m < n);
NSUInteger ret;
do {
ret = random() % m;
} while(ret >= n);
return ret;
}
@implementation NSMutableArray (ArchUtils_Shuffle)
- (void)shuffle {
// http://en.wikipedia.org/wiki/Knuth_shuffle
for(NSUInteger i = [self count]; i > 1; i--) {
NSUInteger j = random_below(i);
[self exchangeObjectAtIndex:i-1 withObjectAtIndex:j];
}
}
@end
Assurez-vous de la graine du générateur de nombres aléatoires (avec, par exemple, srandom(time(NULL))
) peu de temps avant de l'appeler; autrement, la sortie ne sera pas très aléatoire.
Ici il est!
- (NSArray*)shuffleArray:(NSArray*)array {
NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:array];
for(NSUInteger i = [array count]; i > 1; i--) {
NSUInteger j = arc4random_uniform(i);
[temp exchangeObjectAtIndex:i-1 withObjectAtIndex:j];
}
return [NSArray arrayWithArray:temp];
}
Il n'en est pas intégré dans le SDK si c'est ce que vous demandez.
Vous pouvez utiliser n'importe quel randomisation ou brassage de l'algorithme que vous voulez, néanmoins. Différents algorithmes ont différents compromis en termes de l'aléatoire, de l'efficacité, etc.
http://en.wikipedia.org/wiki/Shuffling#Shuffling_algorithms
Pour les algorithmes qui shuffle "sur place" démarrer avec une mutable tableau d'utilisation
insertObject:atIndex:
removeObjectAtIndex:
Pour les algorithmes qui reconstruire le tableau, le nourrir, l'original et de construire un nouveau tableau.
Ma solution est une catégorie de méthode qui retourne une copie du tableau (autoreleased) avec des éléments aléatoires (à l'aide de arc4random).
@interface NSArray (CMRandomised)
/* Returns a copy of the array with elements re-ordered randomly */
- (NSArray *)randomised;
@end
/* Returns a random integer number between low and high inclusive */
static inline int randomInt(int low, int high)
{
return (arc4random() % (high-low+1)) + low;
}
@implementation NSArray (CMRandomised)
- (NSArray *)randomised
{
NSMutableArray *randomised = [NSMutableArray arrayWithCapacity:[self count]];
for (id object in self) {
NSUInteger index = randomInt(0, [randomised count]);
[randomised insertObject:object atIndex:index];
}
return randomised;
}
@end