views:

1997

answers:

4

Is there a canonical way to randomize an array in Objective C?

+2  A: 

There is none built into the SDK if that's what you are asking.

You can use just about any randomization or shuffling algorithm you want however. Different algorithms have different tradeoffs in terms of randomness, efficiency, etc.

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

For algorithms that shuffle "in-place" start with a mutable array use

insertObject:atIndex:
removeObjectAtIndex:

For algorithms that reconstruct the array, feed it the original and build a new array.

Kailoa Kadano
+2  A: 
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().

Nathan Kinsinger
What you wrote doesn't make sense as an instance method. As the code exists, it should just be a function or class method. Idiomatically, it should be an NSArray instance method that returns a new, shuffled array or an NSMutableArray instance method that shuffles itself.
Chuck
True, I was just demonstrating the code here, wasn't really worried about putting it in a category. I also forgot to mention to seed the random() function with srandomdev() or srandom().
Nathan Kinsinger
This code is slightly biased due to the modulo; see http://en.wikipedia.org/wiki/Fisher-Yates_shuffle#Modulo_bias for more about this.
Brent Royal-Gordon
+3  A: 

HowToGenerateARandomOrder

Alex Reynolds
+18  A: 

My utility library defines this category on NSMutableArray to do it:

@interface NSMutableArray (ArchUtils_Shuffle)
- (void)shuffle;
@end

// Unbiased random rounding thingy.
static NSUInteger random_below(NSUInteger n) {
    NSUInteger m = 1;

    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
Brent Royal-Gordon