objective-c - tutorial - objective c vs c++




Choisir un objet aléatoire dans un NSArray (6)

@ La réponse de Darryl est correcte, mais pourrait utiliser quelques modifications mineures:

NSUInteger randomIndex = arc4random() % [theArray count];

Modifications:

  • Utiliser arc4random() sur rand() et random() est plus simple car il ne nécessite pas de semer (appeler srand() ou srandom() ).
  • L' opérateur modulo ( % ) rend l'instruction globale plus courte, tout en la rendant sémantiquement plus claire.
  • theArray.count est faux. Cela fonctionnera, mais count n'est pas déclaré comme @property sur NSArray , et ne devrait donc pas être invoqué via la syntaxe à points. Que cela fonctionne est simplement un effet secondaire de la façon dont la syntaxe point est interprétée par le compilateur.

Dites que j'ai un tableau avec des objets, 1, 2, 3 et 4. Comment choisir un objet aléatoire de ce tableau?


C'est la solution la plus simple que je pourrais trouver:

id object = array.count == 0 ? nil : array[arc4random_uniform(array.count)];

Il est nécessaire de vérifier count car un NSArray non nil mais vide retournera 0 pour count , et arc4random_uniform(0) renvoie 0 . Donc, sans la vérification, vous allez sortir des limites sur le tableau.

Cette solution est tentante, mais elle est incorrecte car elle provoquera un plantage avec un tableau vide:

id object = array[arc4random_uniform(array.count)];

Pour référence, voici la documentation :

u_int32_t
arc4random_uniform(u_int32_t upper_bound);

arc4random_uniform() will return a uniformly distributed random number less than upper_bound.

La page man ne mentionne pas que arc4random_uniform renvoie 0 lorsque 0 est passé comme upper_bound .

En outre, arc4random_uniform est défini dans <stdlib.h> , mais l'ajout de #import n'était pas nécessaire dans mon programme de test iOS.


Générez un nombre aléatoire et utilisez-le comme index. Exemple:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        NSArray *array = [NSArray arrayWithObjects: @"one", @"two", @"three", @"four", nil];
        NSUInteger randomNumber;
        int fd = open("/dev/random", O_RDONLY);
        if (fd != -1) {
            read(fd, &randomNumber, sizeof(randomNumber));
            close(fd);
        } else {
            fprintf(stderr, "Unable to open /dev/random: %s\n", strerror(errno));
            return -1;
        }
        double scaledRandomNumber = ((double)randomNumber)/NSUIntegerMax * [array count];
        NSUInteger randomIndex = (NSUInteger)floor(scaledRandomNumber);
        NSLog(@"random element: %@", [array objectAtIndex: randomIndex]);
    }
    return 0;
}

Peut-être quelque chose du genre:

NSUInteger randomIndex = (NSUInteger)floor(random()/RAND_MAX * [theArray count]);

N'oubliez pas d'initialiser le générateur de nombres aléatoires (srandomdev (), par exemple).

NOTE: J'ai mis à jour pour utiliser -count au lieu de la syntaxe de point, selon la réponse ci-dessous.


@interface NSArray<ObjectType>  (Random)
- (nullable ObjectType)randomObject;
@end

@implementation NSArray (Random)

- (nullable id)randomObject
{
    id randomObject = [self count] ? self[arc4random_uniform((u_int32_t)[self count])] : nil;
    return randomObject;
}

@end

Edit: Mise à jour pour Xcode 7. Generics, nullability


ObjectType *objectVarName = [array objectAtIndex:arc4random_uniform((int)(array.count - 1))];

si vous voulez lancer un int, voici la solution pour cela (utile quand vous avez besoin d'un int aléatoire d'un tableau de nombres non-séquentiels, dans le cas d'un appel enum random, etc.)

int intVarName = (int)[(NSNumber *)[array objectAtIndex:arc4random_uniform((int)(array.count - 1))] integerValue];




cocoa