forma canónica para aleatorizar un NSArray en el Objetivo C

¿Hay alguna manera canónica de aleatorizar una matriz en Objective C?

Mi biblioteca de utilidades define esta categoría en NSMutableArray para hacerlo:

 @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 

Asegúrese de srandom(time(NULL)) generador de números aleatorios (con, por ejemplo, srandom(time(NULL)) ) alguna vez antes de llamarlo; de lo contrario, la salida no será muy aleatoria.

¡Aquí 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]; } 
 if ([array count] > 1) { for (NSUInteger shuffleIndex = [array count] - 1; shuffleIndex > 0; shuffleIndex--) [array exchangeObjectAtIndex:shuffleIndex withObjectAtIndex:random() % (shuffleIndex + 1)]; } 

Asegúrese de inicializar la función random () con srandomdev () o srandom ().

No hay ninguno integrado en el SDK si eso es lo que está preguntando.

Sin embargo, puede usar casi cualquier algoritmo de aleatorización o mezcla que desee. Diferentes algoritmos tienen diferentes compensaciones en términos de aleatoriedad, eficiencia, etc.

http://en.wikipedia.org/wiki/Shuffling#Shuffling_algorithms

Para los algoritmos que se mezclan “en el lugar”, comience con una matriz mutable use

 insertObject:atIndex: removeObjectAtIndex: 

Para los algoritmos que reconstruyen la matriz, aliméntela con la original y construya una nueva matriz.

Mi solución es un método de categoría que devuelve una copia de la matriz (autorrellenada) con elementos aleatorios (usando 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 

No hay una manera canónica sin hacer una categoría en NSArray (es decir, tener un método de instancia como arrayWithRandomizedIndices ) o NSMutableArray (es decir, tener un método como randomizeIndices ).

Aquí hay un ejemplo de mi biblioteca, parte de una categoría en NSMutableArray . Reordenará aleatoriamente la matriz, en lugar de mezclar algunas entradas.

 - (void) randomizeIndices { if (self == nil || [self count] < = 1) { return; } int count = [self count]; NSMutableArray* copySelf = [NSMutableArray arrayWithArray:self]; NSMutableArray* mutableResultArray = [NSMutableArray alloc]; mutableResultArray = [mutableResultArray initWithCapacity:count]; [mutableResultArray autorelease]; int objectsMovedCount = 0; for (int i = 0; i < count; i++) { int index = rand() % (count - objectsMovedCount); id anObject = [copySelf objectAtIndex:index]; [mutableResultArray addObject:anObject]; [copySelf removeObjectAtIndex:index]; objectsMovedCount++; } [self setArray:mutableResultArray]; } 

Call srand(time(0)); o algo así antes de llamar a este método o al inicio del método.

Aleatorización de NSArray como método de categoría Objective-C:

 @implementation NSArray (NGDataDynamics) - (NSArray *)jumbled { NSMutableArray *jumbled = self.mutableCopy; NSUInteger idx = self.count-1; while(idx) { [jumbled exchangeObjectAtIndex:idx withObjectAtIndex:arc4random_uniform(idx)]; idx--; } return jumbled; } @end 

Como se ve: NSArray Aleatorización y Psicodelia