Digamos que tengo una matriz con objetos, 1, 2, 3 y 4. ¿Cómo elegiría un objeto aleatorio de esta matriz?
Digamos que tengo una matriz con objetos, 1, 2, 3 y 4. ¿Cómo elegiría un objeto aleatorio de esta matriz?
Respuestas:
La respuesta de @ Darryl es correcta, pero podría necesitar algunos ajustes menores:
NSUInteger randomIndex = arc4random() % theArray.count;
Modificaciones:
arc4random()
over rand()
y random()
es más simple porque no requiere sembrar (llamar srand()
o srandom()
).%
) hace que la declaración general sea más corta, al mismo tiempo que la hace más clara semánticamente.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 no nil
pero vacío NSArray
volverá 0
para count
, y arc4random_uniform(0)
vuelve 0
. 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
devuelve 0
cuando 0
se pasa como upper_bound
.
Además, arc4random_uniform
está definido en <stdlib.h>
, pero #import
no era necesario agregarlo en mi programa de prueba de iOS.
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.
@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
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;
}
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.
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];
En Swift 4:
let array = ["one","two","three","four"]
let randomNumber = arc4random_uniform(UInt32(array.count))
array[Int(randomNumber)]
arc4random_uniform
método para evitar el sesgo de módulo.