Digamos que tengo una matriz con objetos, 1, 2, 3 y 4. ¿Cómo elegiría un objeto aleatorio de esta matriz?
objective-c
cocoa
Joshua
fuente
fuente
arc4random_uniform
método para evitar el sesgo de módulo.Respuestas:
La respuesta de @ Darryl es correcta, pero podría necesitar algunos ajustes menores:
NSUInteger randomIndex = arc4random() % theArray.count;
Modificaciones:
arc4random()
overrand()
yrandom()
es más simple porque no requiere sembrar (llamarsrand()
osrandom()
).%
) hace que la declaración general sea más corta, al mismo tiempo que la hace más clara semánticamente.fuente
0 % 4 = 0
,1 % 4 = 1
,2 % 4 = 2
,3 % 4 = 3
,4 % 4 = 0
,5 % 4 = 1
... Si Modulo por n , el resultado más grande nunca será mayor que n-1 .count
es una propiedad:@interface NSArray<__covariant ObjectType> : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration> @property (readonly) NSUInteger count;
Esta es la solución más simple que pude encontrar:
id object = array.count == 0 ? nil : array[arc4random_uniform(array.count)];
Es necesario comprobar
count
debido a un nonil
pero vacíoNSArray
volverá0
paracount
, yarc4random_uniform(0)
vuelve0
. Entonces, sin el cheque, saldrá de los límites de la matriz.Esta solución es tentadora pero es incorrecta porque provocará un bloqueo con una matriz vacía:
id object = array[arc4random_uniform(array.count)];
Como referencia, aquí está la documentación :
u_int32_t arc4random_uniform(u_int32_t upper_bound); arc4random_uniform() will return a uniformly distributed random number less than upper_bound.
La página de manual no menciona que
arc4random_uniform
devuelve0
cuando0
se pasa comoupper_bound
.Además,
arc4random_uniform
está definido en<stdlib.h>
, pero#import
no era necesario agregarlo en mi programa de prueba de iOS.fuente
Quizás algo parecido a:
NSUInteger randomIndex = (NSUInteger)floor(random()/RAND_MAX * [theArray count]);
No olvide inicializar el generador de números aleatorios (srandomdev (), por ejemplo).
NOTA: He actualizado para usar -count en lugar de la sintaxis de puntos, según la respuesta a continuación.
fuente
@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
Editar: actualizado para Xcode 7. Genéricos, nulabilidad
fuente
Genere un número aleatorio y utilícelo como índice. Ejemplo:
#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; }
fuente
SecRandomCopyBytes()
para obtener números aleatorios criptográficamente útiles, en el iPhone de todos modos. En Mac, tiene acceso directo a / dev / random.srand([[NSDate date] timeIntervalSince1970]); int inx =rand()%[array count];
inx es el número aleatorio.
donde srand () puede estar en cualquier lugar del programa antes de la función de selección aleatoria.
fuente
ObjectType *objectVarName = [array objectAtIndex:arc4random_uniform((int)(array.count - 1))];
si desea convertir eso en un int, aquí está la solución para eso (útil para cuando necesita un int aleatorio de una matriz de números no secuenciales, en el caso de aleatorizar una llamada enum, etc.)
int intVarName = (int)[(NSNumber *)[array objectAtIndex:arc4random_uniform((int)(array.count - 1))] integerValue];
fuente
En Swift 4:
let array = ["one","two","three","four"] let randomNumber = arc4random_uniform(UInt32(array.count)) array[Int(randomNumber)]
fuente