Выбор случайного объекта в NSArray

Скажем, у меня есть массив с объектами, 1, 2, 3 и 4. Как бы я выбрал случайный объект из этого массива?

Ответ 1

@Даррил ответил правильно, но может использовать некоторые незначительные настройки:

NSUInteger randomIndex = arc4random() % [theArray count];

Модификации:

  • Использование arc4random() над rand() и random() проще, потому что не требует посева (вызов srand() или srandom()).
  • Оператор modulo (%) делает общий оператор короче, а также делает его семантически понятным.
  • theArray.count неверно. Он будет работать, но count не объявляется как @property на NSArray, и поэтому не вызывается через точечный синтаксис. То, что он работает, просто является побочным эффектом интерпретации синтаксиса точки компилятором.

Ответ 2

Это самое простое решение, которое я мог бы придумать:

id object = array.count == 0 ? nil : array[arc4random_uniform(array.count)];

Необходимо проверить count, потому что не nil, но пустой NSArray вернет 0 для count, а arc4random_uniform(0) возвращает 0. Поэтому без проверки вы выйдете за пределы массива.

Это решение заманчиво, но неверно, потому что это приведет к сбою с пустым массивом:

id object = array[arc4random_uniform(array.count)];

Для справки: documentation:

u_int32_t
arc4random_uniform(u_int32_t upper_bound);

arc4random_uniform() will return a uniformly distributed random number less than upper_bound.

В man-странице не упоминается, что arc4random_uniform возвращает 0, когда 0 передается как upper_bound.

Кроме того, arc4random_uniform определяется в <stdlib.h>, но добавление #import не было необходимо в моей тестовой программе iOS.

Ответ 3

Возможно, что-то похожее:

NSUInteger randomIndex = (NSUInteger)floor(random()/RAND_MAX * [theArray count]);

Не забудьте инициализировать генератор случайных чисел (например, srandomdev()).

ПРИМЕЧАНИЕ. Я обновил для использования -count вместо синтаксиса точки в соответствии с нижеприведенным ответом.

Ответ 4

@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

Изменить: Обновлено для Xcode 7. Дженерики, nullability

Ответ 5

Создайте случайное число и используйте его как индекс. Пример:

#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;
}

Ответ 6

 srand([[NSDate date]  timeIntervalSince1970]);

 int inx =rand()%[array count];

inx - случайное число.

где srand() может быть где угодно в программе перед функцией случайного выбора.

Ответ 7

ObjectType *objectVarName = [array objectAtIndex:arc4random_uniform((int)(array.count - 1))];

если вы хотите передать это в int, вот решение для этого (полезно, когда вам нужен случайный int из массива несекретных чисел, в случае рандомизации вызова enum и т.д.)

int intVarName = (int)[(NSNumber *)[array objectAtIndex:arc4random_uniform((int)(array.count - 1))] integerValue];

Ответ 8

В Swift 4:

let array = ["one","two","three","four"]
let randomNumber = arc4random_uniform(UInt32(array.count))

array[Int(randomNumber)]