Is there a canonical way to randomize an array in Objective-C?
-
1possible duplicate of [What's the Best Way to Shuffle an NSMutableArray?](http://stackoverflow.com/questions/56648/whats-the-best-way-to-shuffle-an-nsmutablearray) – Senseful Jan 29 '15 at 01:35
-
1Recommendation is [Fisher-Yates](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle) for NSMutableArray: `for (NSUInteger i = self.count; i > 1; i--) [self exchangeObjectAtIndex:i - 1 withObjectAtIndex:arc4random_uniform((u_int32_t)i)];` – Cœur Nov 21 '15 at 07:21
7 Answers
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.

- 17,541
- 7
- 56
- 91
-
Love it! Thanks for sharing. I'm extremely curious about the rest of your utility library now. – PEZ Jan 11 '11 at 19:51
-
Most of it's not algorithmic--it's everything from +[NSArray arrayWithCount:numbers:] (where the "numbers" are doubles) to -[UIView moveToSuperview:withFrame:animated:], plus a single-object Core Data stack for kicks. – Becca Royal-Gordon Jan 11 '11 at 20:04
-
This doesn't work for me. I mean it shuffles "a little" but some parts are still in order. Also given the same array the first shuffle has always the same outcome. It is therefore not really random. – Apr 09 '11 at 15:09
-
6@bresc either seed random with `srandom(time(NULL))` or use `arc4random()` instead – Bartosz Ciechanowski Apr 27 '11 at 19:09
-
-
1Just a small thing I added: `if (n == 0) { return 0; }`. You could just not pass 0 but if you do you get trapped in that second loop. – jasongregori Sep 20 '11 at 00:22
-
12If you are using OSX 10.7 or iOS 4.3 or later you can use `arc4random_uniform(upper_bound)` and not have to write or use the `random_below(i)` function. – LavaSlider Jan 16 '12 at 14:20
-
1@LavaSlider Good point! Here's the implementation http://stackoverflow.com/a/10258341/396133 – Abramodj Apr 21 '12 at 11:02
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];
}

- 5,709
- 9
- 49
- 75
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().

- 23,641
- 2
- 30
- 19
-
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 Apr 26 '09 at 18:41
-
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 Apr 26 '09 at 19:24
-
2This code is slightly biased due to the modulo; see http://en.wikipedia.org/wiki/Fisher-Yates_shuffle#Modulo_bias for more about this. – Becca Royal-Gordon Apr 26 '09 at 22:36
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.

- 10,045
- 1
- 36
- 33
My solution is a category method that returns a copy of the array (autoreleased) with elements randomised (using 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

- 7,346
- 2
- 37
- 34
NSArray randomization as Objective-C category method:
@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
As seen: NSArray Randomization & Psychedelia

- 10,028
- 6
- 55
- 74
There isn't a canonical way without making a category on NSArray
(i.e. have an instance method like arrayWithRandomizedIndices
) or NSMutableArray
(i.e. have a method like randomizeIndices
).
Here's an example from my library, part of a category on NSMutableArray
. It will randomly reorder the array, rather than shuffle a few entries.
- (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));
or some such before calling this method or early in the method.

- 30,811
- 34
- 116
- 155