Powiedzmy, że mam tablicę z obiektami 1, 2, 3 i 4. Jak wybrać losowy obiekt z tej tablicy?
Powiedzmy, że mam tablicę z obiektami 1, 2, 3 i 4. Jak wybrać losowy obiekt z tej tablicy?
Odpowiedzi:
Odpowiedź @ Darryl jest poprawna, ale przydałoby się kilka drobnych poprawek:
NSUInteger randomIndex = arc4random() % theArray.count;
Modyfikacje:
arc4random()
over rand()
i random()
jest prostsze, ponieważ nie wymaga inicjowania (wywoływania srand()
lub srandom()
).%
) sprawia, że ogólny rachunek krótsze, a jednocześnie czyni go semantycznie jaśniejsze.0 % 4 = 0
, 1 % 4 = 1
, 2 % 4 = 2
, 3 % 4 = 3
, 4 % 4 = 0
, 5 % 4 = 1
... Jeśli modulo przez n , twój największy wynik nigdy nie będzie większa niż n-1 .
count
jest to właściwość:@interface NSArray<__covariant ObjectType> : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration> @property (readonly) NSUInteger count;
Oto najprostsze rozwiązanie, jakie mogłem wymyślić:
id object = array.count == 0 ? nil : array[arc4random_uniform(array.count)];
Konieczne jest sprawdzenie, count
ponieważ nil
niepusty, ale NSArray
wróci 0
do count
i arc4random_uniform(0)
wróci 0
. Więc bez sprawdzenia wyjdziesz poza granice tablicy.
To rozwiązanie jest kuszące, ale jest błędne, ponieważ spowoduje awarię z pustą tablicą:
id object = array[arc4random_uniform(array.count)];
W celach informacyjnych, oto dokumentacja :
u_int32_t
arc4random_uniform(u_int32_t upper_bound);
arc4random_uniform() will return a uniformly distributed random number less than upper_bound.
Strona podręcznika nie wspomina, że arc4random_uniform
zwraca, 0
gdy 0
jest przekazywana jako upper_bound
.
Jest również arc4random_uniform
zdefiniowany w programie <stdlib.h>
, ale dodanie #import
nie było konieczne w moim programie testowym na iOS.
Być może coś w rodzaju:
NSUInteger randomIndex = (NSUInteger)floor(random()/RAND_MAX * [theArray count]);
Nie zapomnij zainicjować generatora liczb losowych (na przykład srandomdev ()).
UWAGA: Zaktualizowałem, aby używać -count zamiast składni kropek, zgodnie z odpowiedzią poniżej.
@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
Edycja: zaktualizowano dla Xcode 7. Generics, nullability
Wygeneruj liczbę losową i użyj jej jako indeksu. Przykład:
#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()
aby uzyskać przydatne kryptograficznie liczby losowe, i tak na iPhonie. Na Macu masz bezpośredni dostęp do / dev / random.
srand([[NSDate date] timeIntervalSince1970]);
int inx =rand()%[array count];
inx to liczba losowa.
gdzie srand () może znajdować się w dowolnym miejscu programu przed funkcją losowego wybierania.
ObjectType *objectVarName = [array objectAtIndex:arc4random_uniform((int)(array.count - 1))];
jeśli chcesz rzutować to na int, oto rozwiązanie tego problemu (przydatne, gdy potrzebujesz losowej liczby int z tablicy liczb niesekwencyjnych, w przypadku losowego wywołania wyliczenia itp.)
int intVarName = (int)[(NSNumber *)[array objectAtIndex:arc4random_uniform((int)(array.count - 1))] integerValue];
W Swift 4:
let array = ["one","two","three","four"]
let randomNumber = arc4random_uniform(UInt32(array.count))
array[Int(randomNumber)]
arc4random_uniform
metody, aby uniknąć odchylenia modulo.