2009-04-26 14 views
38

Nesne C'deki bir diziyi rasgele hale getirmenin kanonik bir yolu var mı?Nesne C'deki bir NSArray'ı rasgele birleştirme yolu kuralı

+1

olası yinelenen [Ne bir NSMutableArray karıştır'ın en iyi yol değil mi?] (Http: // stackoverflow .com/questions/56648/whats-the-best-way-to-shuffle-an-nsmutablearray) – Senseful

+1

Öneri [Fisher-Yates] (https://en.wikipedia.org/wiki/Fisher%E2%80% NSMutableArray için: 93Yates_shuffle: için (NSUInteger i = self.count; i> 1; i--) [self exchangeObjectAtIndex: i - 1 ile ObjectAtIndex: arc4random_uniform ((u_int32_t) i)]; ' –

cevap

59

Benim araç kütüphanesi bunu yapmak için NSMutableArray bu kategoriyi tanımlar:

@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's 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's 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 

Eğer diyoruz bazen önce (ör srandom(time(NULL)) ile) rasgele sayı üreticisinin emin olun; aksi halde çıktı çok rasgele olmaz.

+0

Love it! Paylaşım için teşekkürler. Artık yardımcı program kütüphanenizin geri kalanını çok merak ediyorum. – PEZ

+0

Çoğu algoritmik değil - + [NSArray arrayWithCount: sayılar:] ("sayılar" iki katına çıkar)) - [UIView moveToSuperview: withFrame: animated:], artı tek nesne Çekirdek Veri yığını . –

+0

Bu benim için çalışmıyor. Demek istediğim "biraz" karıştırıyor ama bazı bölümler hâlâ sıralanıyor. Aynı dizi verildiğinde, ilk karıştırmanın her zaman aynı sonucu vardır. Bu nedenle gerçekten rastgele değil. –

2

Sormak istediğiniz şey SDK'ya yerleşik değil.

Ancak istediğiniz herhangi bir rasgele seçim veya karıştırma algoritmasını kullanabilirsiniz. Farklı algoritmalar

http://en.wikipedia.org/wiki/Shuffling#Shuffling_algorithms

"yerinde" karıştır algoritmalar için yeniden algoritmalar için

insertObject:atIndex: 
removeObjectAtIndex: 

kullandığınız bir değişken dizisi ile başlar, vb rasgelelik, verimlilik açısından farklı eksikleri var dizi, orijinali besleyin ve yeni bir dizi oluşturun.

7
if ([array count] > 1) { 
    for (NSUInteger shuffleIndex = [array count] - 1; shuffleIndex > 0; shuffleIndex--) 
     [array exchangeObjectAtIndex:shuffleIndex withObjectAtIndex:random() % (shuffleIndex + 1)]; 
} 

Random() işlevini srandomdev() veya srandom() ile eklediğinizden emin olun.

+0

Yazdıklarınız örnek yöntem olarak anlam ifade etmiyor. Kod mevcut olduğundan, yalnızca bir işlev veya sınıf yöntemi olmalıdır. Idiomatically, kendisini karıştırır yeni, karıştırılmış dizi veya bir NSMutableArray örnek yöntemi döndüren bir NSArray örnek yöntemi olmalıdır. – Chuck

+0

Doğru, sadece buradaki kodu göstermekteydim, bir kategoriye koyma konusunda endişelenmemiştim. Ayrıca srandomdev() veya srandom() ile random() işlevini tohumlamaktan bahsetmeyi unuttum. –

+2

Bu kod, modulo nedeniyle biraz önyargılıdır; Bu konuda daha fazla bilgi için http://en.wikipedia.org/wiki/Fisher-Yates_shuffle#Modulo_bias sayfasına bakın. –

0

kurallı NSArray bir kategori yapmadan bir şekilde (yani arrayWithRandomizedIndices gibi bir örnek yöntemi sahip) ya da NSMutableArray (yani randomizeIndices gibi bir yöntem varsa) mevcut değildir.

Kitaplığımdan, NSMutableArray numaralı telefondan bir bölümün bir örneği. Birkaç girişi karıştırmak yerine diziyi rasgele yeniden sıralar.

- (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]; 
} 

Çağrı srand(time(0)); veya erken yönteminde bu yöntemi veya çağırmadan önce bazı tür.

1

Çözümüm, dizinin bir kopyasını rastgele (arc4random kullanarak) öğelerle döndüren bir kategori yöntemidir.

@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 
20

İşte işte burada!

- (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]; 
} 
0
Objective-C kategorisi yöntemi olarak

NSArray randomizasyon: As

@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 

görülme: NSArray Randomization & Psychedelia

ait