38 votes

manière canonique de générer aléatoirement un NSArray en Objective-C

Est-il une manière canonique de générer aléatoirement un tableau en Objective-C?

59voto

Brent Royal-Gordon Points 8044

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.

20voto

Abramodj Points 1771

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];
}

7voto

Nathan Kinsinger Points 6202
if ([array count] > 1) {
    for (NSUInteger shuffleIndex = [array count] - 1; shuffleIndex > 0; shuffleIndex--)
        [array exchangeObjectAtIndex:shuffleIndex withObjectAtIndex:random() % (shuffleIndex + 1)];
}

Assurez-vous de la graine aléatoire() la fonction soit avec srandomdev() ou srandom().

2voto

amattn Points 7908

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.

1voto

Chris Miles Points 2504

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X