canonical way to randomize an NSArray in Objective-C
My utility library defines this category on NSMutableArray to do it:
@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
Make sure you seed the random number generator (with e.g. srandom(time(NULL))
) sometime before you call it; otherwise the output won't be very random.
Here it is!
- (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)];}
Make sure to seed the random() function with either srandomdev() or srandom().