强制洗牌NSMutableArray

4

我有一个名为putNumberUsed的NSMutableArray。它包含以下对象:@"blah1,@"blah2",@"blah3",@"blah4"。我想要随机洗牌这些对象,例如如果我选择:

 [putNumberUsed objectAtIndex:0] 

它只会给我“blah1”之外的任何东西。 我该怎么做呢?以下是我到目前为止使用的代码:

NSMutableArray *putNumbersUsed = [[NSMutableArray alloc] arrayWithObjects:@"blah1",@"blah2",@"blah3",@"blah4",nil];

可能是重复的 - https://dev59.com/S2035IYBdhLWcg3wC7cR - Peter Kelly
可能是如何对NSMutableArray进行最佳洗牌?的重复问题。 - David Rönnqvist
6个回答

9
我认为,您可以编写一个循环来实现。请查看以下代码:
for (int i = 0; i < putNumberUsed.count; i++) {
    int randomInt1 = arc4random() % [putNumberUsed count];
    int randomInt2 = arc4random() % [putNumberUsed count];
    [putNumberUsed exchangeObjectAtIndex:randomInt1 withObjectAtIndex:randomInt2];
}

我认为这对你可能有用。

6
算法不太好。只使用一个随机索引并将该索引处的对象与位置在 i 处的对象交换。 - onegray
是的,你说得对onegray,我们可以仅使用一个随机值。 - Rajesh
另外,不要在随机值上使用%,这会破坏分布。请改用arc4random_uniform()。 - Michael Morris

5

这是一个洗牌解决方案,当计数> 1时,所有位置都被强制更改。

添加一个类别,例如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

然后你可以像这样洗牌:
[putNumbersUsed unstableShuffle];

这个解决方案:

Swift 3.2 和 Swift 4 的等效版本是:

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

Swift 3.0和3.1的等效版本是:

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)))])
        }
    }
}

注意:有关正常洗牌算法(其中可能存在相同位置的结果)的算法也可用

3

苹果公司在iOS 10.x++中推出了关于数组随机排序的新概念

您需要导入框架:

ObjecC

#import <GameplayKit/GameplayKit.h>

NSArray *shuffledArray = [yourArray shuffledArray];

Swift

import GameplayKit

let shuffledArray = yourArray.shuffled()

这并没有回答问题:那些方法可能会返回一个未修改的数组,这不是被问到的内容。 - Cœur

2
您可以使用以下代码来对对象进行洗牌:

[putNumbersUsed exchangeObjectAtIndex:3 withObjectAtIndex:0];

我认为这可能对你有用。


2
谢谢你,Rajesh。我一直在寻找这样的东西,但这只是将对象在3和0之间交换,如果我想随机地对所有对象进行操作怎么办?谢谢! - Alex G
是的,你说得对。但我认为Rajesh想引导你走向正确的方向。我在我的答案中发布了一个非常相似的代码,所以看一下吧。 - Fabio Poloni

1

生成一个随机数作为索引

int randomInt = arc4random() % [putNumberUsed count];
[putNumberUsed objectAtIndex:randomInt];

如果同一个索引被多次生成怎么办?0_o - Ahmad Al-Attal

0

使用这个:

for (int i = 0; i < [putNumberUsed count]; i++) {
    int random = arc4random() % [putNumberUsed count]; 
    [putNumbersUsed exchangeObjectAtIndex:random withObjectAtIndex:i]; 
}

1
每次迭代都必须重新计算随机数!! - ragnarius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接