Force Shuffle NSMutableArray

前端 未结 6 962
深忆病人
深忆病人 2021-01-13 14:03

I have a NSMutableArray called putNumberUsed. It contains the following objects @\"blah1,@\"blah2\",@\"blah3\",@\"blah4\". I want to shuffle these objects randomly so for ex

6条回答
  •  星月不相逢
    2021-01-13 14:27

    Here is a shuffling solution with all positions forced to change when count > 1.

    Add a category like NSMutableArray+Shuffle.m:

    @implementation NSMutableArray (Shuffle)
    // Fisher-Yates shuffle variation with all positions forced to change
    - (void)unstableShuffle
    {
        for (NSInteger i = self.count - 1; i > 0; i--)
            // note: we use u_int32_t because `arc4random_uniform` doesn't support int64
            [self exchangeObjectAtIndex:i withObjectAtIndex:arc4random_uniform((u_int32_t)i)];
    }
    @end
    

    Then you can shuffle like:

    [putNumbersUsed unstableShuffle];
    

    This solution:

    • has no modulo bias
    • has no naive bias
    • has no sorting bias

    A Swift 3.2 and Swift 4 equivalent is:

    extension Array {
        mutating func unstableShuffle() {
            for i in stride(from: count - 1, to: 0, by: -1) {
                swapAt(i, Int(arc4random_uniform(UInt32(i))))
            }
        }
    }
    

    A Swift 3.0 and 3.1 equivalent is:

    extension Array {
        mutating func unstableShuffle() {
            for i in stride(from: count - 1, to: 0, by: -1) {
                swap(&self[i], &self[Int(arc4random_uniform(UInt32(i)))])
            }
        }
    }
    

    Note: An algorithm for regular shuffling (where a result with same positions being possible) is also available

提交回复
热议问题