2009-04-26 10 views
38

Objective Cで配列をランダム化する正規の方法はありますか?Objective CでNSArrayをランダムに正規化する方法

+1

の可能重複[NSMutableArrayのをシャッフルするための最良の方法は何?](のhttp:// stackoverflowの.com/questions/56648/whats-the-best-way-to-shuffle-an-nsmutablearray) – Senseful

+1

おすすめは[Fisher-Yates](https://en.wikipedia.org/wiki/Fisher%E2%80%)です。 93Yates_shuffle)for NSMutableArray: 'for(NSUInteger i = self.count; i> 1; i--)[self exchangeObjectAtIndex:i - 1 with ObjectAtIndex:arc4random_uniform((u_int32_t)i)]; ' –

答えて

59

マイユーティリティライブラリは、それを行うには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'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 

あなたはそれを呼び出すいつか前に、あなたが(例えばsrandom(time(NULL))付き)乱数生成器にシードを確認してください。そうでなければ、出力はあまりランダムではありません。

+0

それを愛する!共有してくれてありがとう。私はあなたのユーティリティライブラリの残りの部分について非常に不思議です。 – PEZ

+0

ほとんどのものはアルゴリズムではありません。+ [NSArray arrayWithCount:numbers:]( "numbers"は2倍です)から - [UIView moveToSuperview:withFrame:animated:]、さらにキックのための単一オブジェクトのコアデータスタック。 –

+0

これは私のためには機能しません。私はそれが "少し"シャッフルを意味しますが、いくつかの部分はまだ順序です。同じ配列を与えられても、最初のシャッフルは常に同じ結果を示します。したがって、実際にはランダムではありません。 –

2

あなたが求めているのであれば、SDKには何も組み込まれていません。

ただし、任意のランダム化アルゴリズムやシャッフルアルゴリズムを使用できます。異なるアルゴリズムは

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

「インプレース」シャッフルアルゴリズムのために再構築したアルゴリズムについて

insertObject:atIndex: 
removeObjectAtIndex: 

を使用する可変配列で始まるなど、ランダム性、効率の点で異なるトレードオフを持っていますそれを元に戻し、新しい配列を作成します。

7

random()関数にsrandomdev()またはsrandom()を指定してください。

+0

あなたが書いたことは、インスタンスメソッドとしては意味がありません。コードが存在するので、関数またはクラスメソッドでなければなりません。慣習的には、シャッフルされた新しい配列、またはシャッフルするNSMutableArrayインスタンスメソッドを返すNSArrayインスタンスメソッドでなければなりません。 – Chuck

+0

本当に、私はここでコードをデモしていただけで、カテゴリに入れることを心配していませんでした。 random()関数をsrandomdev()またはsrandom()でシードすることについても言及していませんでした。 –

+2

このコードはモジュロによってわずかに偏っています。詳しくは、http://en.wikipedia.org/wiki/Fisher-Yates_shuffle#Modulo_biasを参照してください。 –

0

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));または早期の方法でこのメソッドまたはを呼び出す前に、いくつかのように。

1

私の解決策は、(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 
20

ここにあります!

@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 

見られるように:Objective-Cのカテゴリ方法として

- (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]; 
} 
関連する問題