Giả sử tôi có một mảng với các đối tượng, 1, 2, 3 và 4. Làm cách nào để chọn một đối tượng ngẫu nhiên từ mảng này?
Giả sử tôi có một mảng với các đối tượng, 1, 2, 3 và 4. Làm cách nào để chọn một đối tượng ngẫu nhiên từ mảng này?
Câu trả lời:
Câu trả lời của @ Darryl là đúng, nhưng có thể sử dụng một số chỉnh sửa nhỏ:
NSUInteger randomIndex = arc4random() % theArray.count;
Các sửa đổi:
arc4random()
over rand()
và random()
đơn giản hơn vì nó không yêu cầu seeding (gọi srand()
hoặc srandom()
).%
) làm báo cáo kết quả tổng thể ngắn hơn, đồng thời cũng làm cho nó ngữ nghĩa rõ ràng hơn.0 % 4 = 0
, 1 % 4 = 1
, 2 % 4 = 2
, 3 % 4 = 3
, 4 % 4 = 0
, 5 % 4 = 1
... Nếu bạn modulo bởi n , kết quả lớn nhất của bạn sẽ không bao giờ lớn hơn n-1 .
count
là một tài sản:@interface NSArray<__covariant ObjectType> : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration> @property (readonly) NSUInteger count;
Đây là giải pháp đơn giản nhất mà tôi có thể đưa ra:
id object = array.count == 0 ? nil : array[arc4random_uniform(array.count)];
Đó là cần thiết để kiểm tra count
vì một phi nil
nhưng trống rỗng NSArray
sẽ trở lại 0
cho count
, và arc4random_uniform(0)
lợi nhuận 0
. Vì vậy, nếu không có séc, bạn sẽ đi ra ngoài giới hạn trên mảng.
Giải pháp này rất hấp dẫn nhưng sai vì nó sẽ gây ra sự cố với một mảng trống:
id object = array[arc4random_uniform(array.count)];
Để tham khảo, đây là tài liệu :
u_int32_t
arc4random_uniform(u_int32_t upper_bound);
arc4random_uniform() will return a uniformly distributed random number less than upper_bound.
Trang người đàn ông không đề cập rằng arc4random_uniform
trả về 0
khi 0
được thông qua như upper_bound
.
Ngoài ra, arc4random_uniform
được định nghĩa trong <stdlib.h>
, nhưng việc thêm #import
không cần thiết trong chương trình thử nghiệm iOS của tôi.
Có lẽ điều gì đó dọc theo dòng:
NSUInteger randomIndex = (NSUInteger)floor(random()/RAND_MAX * [theArray count]);
Đừng quên khởi tạo trình tạo số ngẫu nhiên (ví dụ: srandomdev ()).
LƯU Ý: Tôi đã cập nhật để sử dụng -count thay vì cú pháp dấu chấm, theo câu trả lời bên dưới.
@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
Chỉnh sửa: Đã cập nhật cho Xcode 7. Generics, nullability
Tạo một số ngẫu nhiên và sử dụng nó làm chỉ mục. Thí dụ:
#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()
để nhận các số ngẫu nhiên hữu ích về mặt mật mã, trên iPhone. Trên Mac, bạn có quyền truy cập trực tiếp vào / dev / random.
srand([[NSDate date] timeIntervalSince1970]);
int inx =rand()%[array count];
inx là số ngẫu nhiên.
trong đó srand () có thể ở bất kỳ đâu trong chương trình trước hàm chọn ngẫu nhiên.
ObjectType *objectVarName = [array objectAtIndex:arc4random_uniform((int)(array.count - 1))];
nếu bạn muốn chuyển nó thành một int, đây là giải pháp cho điều đó (hữu ích khi bạn cần một int ngẫu nhiên từ một mảng các số không tuần tự, trong trường hợp ngẫu nhiên một lệnh gọi enum, v.v.)
int intVarName = (int)[(NSNumber *)[array objectAtIndex:arc4random_uniform((int)(array.count - 1))] integerValue];
Trong Swift 4:
let array = ["one","two","three","four"]
let randomNumber = arc4random_uniform(UInt32(array.count))
array[Int(randomNumber)]
arc4random_uniform
phương pháp này để tránh sai lệch modulo.