Disons que j'ai un tableau avec des objets, 1, 2, 3 et 4. Comment choisirais-je un objet aléatoire dans ce tableau?
objective-c
cocoa
Joshua
la source
la source
arc4random_uniform
méthode pour éviter les biais modulo.Réponses:
La réponse de @ Darryl est correcte, mais pourrait nécessiter quelques ajustements mineurs:
NSUInteger randomIndex = arc4random() % theArray.count;
Modifications:
arc4random()
overrand()
andrandom()
est plus simple car elle ne nécessite pas d'amorçage (appelsrand()
ousrandom()
).%
) rend l'instruction globale plus courte, tout en la rendant sémantiquement plus claire.la source
0 % 4 = 0
,1 % 4 = 1
,2 % 4 = 2
,3 % 4 = 3
,4 % 4 = 0
,5 % 4 = 1
... Si vous modulo par n , votre plus grand résultat ne sera jamais supérieure à n-1 .count
est une propriété:@interface NSArray<__covariant ObjectType> : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration> @property (readonly) NSUInteger count;
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 non-nil
mais videNSArray
retournera0
pourcount
etarc4random_uniform(0)
retourne0
. Donc, sans le chèque, vous sortirez des limites du tableau.Cette solution est tentante mais est erronée car elle provoquera un crash 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 de manuel ne mentionne pas que
arc4random_uniform
renvoie0
quand0
est passé commeupper_bound
.Aussi,
arc4random_uniform
est défini dans<stdlib.h>
, mais l'ajout#import
n'était pas nécessaire dans mon programme de test iOS.la source
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).
REMARQUE: j'ai mis à jour pour utiliser -count au lieu de la syntaxe dot, conformément à la réponse ci-dessous.
la source
@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: mis à jour pour Xcode 7. Generics, nullability
la source
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; }
la source
SecRandomCopyBytes()
pour obtenir des nombres aléatoires cryptographiquement utiles, sur l'iPhone de toute façon. Sur Mac, vous avez un accès direct à / dev / random.srand([[NSDate date] timeIntervalSince1970]); int inx =rand()%[array count];
inx est le nombre aléatoire.
où srand () peut être n'importe où dans le programme avant la fonction de sélection aléatoire.
la source
ObjectType *objectVarName = [array objectAtIndex:arc4random_uniform((int)(array.count - 1))];
si vous voulez convertir cela en un int, voici la solution pour cela (utile lorsque vous avez besoin d'un int aléatoire à partir d'un tableau de nombres non séquentiels, dans le cas de la randomisation d'un appel enum, etc.)
int intVarName = (int)[(NSNumber *)[array objectAtIndex:arc4random_uniform((int)(array.count - 1))] integerValue];
la source
Dans Swift 4:
let array = ["one","two","three","four"] let randomNumber = arc4random_uniform(UInt32(array.count)) array[Int(randomNumber)]
la source