Существует ли канонический способ рандомизации массива в Objective C?
Канонический способ рандомизации NSArray в Objective C
Ответ 1
Моя библиотека утилиты определяет эту категорию в NSMutableArray для этого:
@interface NSMutableArray (ArchUtils_Shuffle)
- (void)shuffle;
@end
// Chooses a random integer below n without bias.
// Computes m, a power of two slightly above n, and takes random() modulo m,
// then throws away the random number if it between n and m.
// (More naive techniques, like taking random() modulo n, introduce a bias
// towards smaller numbers in the range.)
static NSUInteger random_below(NSUInteger n) {
NSUInteger m = 1;
// Compute smallest power of two greater than n.
// There probably a faster solution than this loop, but bit-twiddling
// isn't my specialty.
do {
m <<= 1;
} while(m < n);
NSUInteger ret;
do {
ret = random() % m;
} while(ret >= n);
return ret;
}
@implementation NSMutableArray (ArchUtils_Shuffle)
- (void)shuffle {
// http://en.wikipedia.org/wiki/Knuth_shuffle
for(NSUInteger i = [self count]; i > 1; i--) {
NSUInteger j = random_below(i);
[self exchangeObjectAtIndex:i-1 withObjectAtIndex:j];
}
}
@end
Перед тем, как позвонить, убедитесь, что вы запустили генератор случайных чисел (например, srandom(time(NULL))
); в противном случае вывод будет не очень случайным.
Ответ 2
Вот оно!
- (NSArray*)shuffleArray:(NSArray*)array {
NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:array];
for(NSUInteger i = [array count]; i > 1; i--) {
NSUInteger j = arc4random_uniform(i);
[temp exchangeObjectAtIndex:i-1 withObjectAtIndex:j];
}
return [NSArray arrayWithArray:temp];
}
Ответ 3
if ([array count] > 1) {
for (NSUInteger shuffleIndex = [array count] - 1; shuffleIndex > 0; shuffleIndex--)
[array exchangeObjectAtIndex:shuffleIndex withObjectAtIndex:random() % (shuffleIndex + 1)];
}
Обязательно запустите функцию random() с помощью srandomdev() или srandom().
Ответ 4
В SDK нет встроенного SDK, если это то, о чем вы просите.
Вы можете использовать практически любой алгоритм рандомизации или перетасовки, который вы хотите. Различные алгоритмы имеют разные компромиссы с точки зрения случайности, эффективности и т.д.
http://en.wikipedia.org/wiki/Shuffling#Shuffling_algorithms
Для алгоритмов, которые перетасовывают "на месте", начинаются с изменяемого массива, используйте
insertObject:atIndex:
removeObjectAtIndex:
Для алгоритмов, которые восстанавливают массив, передайте его оригиналу и создайте новый массив.
Ответ 5
Мое решение - это метод категории, который возвращает копию массива (autoreleased) с рандомизированными элементами (используя arc4random).
@interface NSArray (CMRandomised)
/* Returns a copy of the array with elements re-ordered randomly */
- (NSArray *)randomised;
@end
/* Returns a random integer number between low and high inclusive */
static inline int randomInt(int low, int high)
{
return (arc4random() % (high-low+1)) + low;
}
@implementation NSArray (CMRandomised)
- (NSArray *)randomised
{
NSMutableArray *randomised = [NSMutableArray arrayWithCapacity:[self count]];
for (id object in self) {
NSUInteger index = randomInt(0, [randomised count]);
[randomised insertObject:object atIndex:index];
}
return randomised;
}
@end
Ответ 6
Нет канонического способа без создания категории на NSArray
(т.е. иметь метод экземпляра типа arrayWithRandomizedIndices
) или NSMutableArray
(т.е. иметь такой метод, как randomizeIndices
).
Вот пример из моей библиотеки, часть категории на NSMutableArray
. Он будет случайным образом изменять порядок массива, а не перетасовывать несколько записей.
- (void) randomizeIndices
{
if (self == nil || [self count] <= 1)
{
return;
}
int count = [self count];
NSMutableArray* copySelf = [NSMutableArray arrayWithArray:self];
NSMutableArray* mutableResultArray = [NSMutableArray alloc];
mutableResultArray = [mutableResultArray initWithCapacity:count];
[mutableResultArray autorelease];
int objectsMovedCount = 0;
for (int i = 0; i < count; i++)
{
int index = rand() % (count - objectsMovedCount);
id anObject = [copySelf objectAtIndex:index];
[mutableResultArray addObject:anObject];
[copySelf removeObjectAtIndex:index];
objectsMovedCount++;
}
[self setArray:mutableResultArray];
}
Вызов srand(time(0));
или некоторые из них перед вызовом этого метода или в начале метода.
Ответ 7
Рандомизация NSArray как метод Objective-C:
@implementation NSArray (NGDataDynamics)
- (NSArray *)jumbled
{
NSMutableArray *jumbled = self.mutableCopy;
NSUInteger idx = self.count-1;
while(idx)
{
[jumbled exchangeObjectAtIndex:idx
withObjectAtIndex:arc4random_uniform(idx)];
idx--;
}
return jumbled;
}
@end
Как видно: NSArray Randomization и Psychedelia