关于swift:我怎么能不重复已经生成的随机数?

How can I never repeat a already generated random number?

本问题已经有最佳答案,请猛点这里访问。

如何使arc4random()集中的随机生成的数字永不重复?例如,在arc4random(100)中,选择1,它将不再被提起。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var card: UIImageView!

    @IBOutlet weak var nextButton: UIButton!


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }




    @IBAction func nextCardTapped(sender: UIButton) {



        //Edit number of cards here for the random card to show up
        var randomCard = arc4random_uniform(100)
        // Edit number of cards here for the random card to show up


        var randomCardString:String = String(format:"card%i", randomCard)


        self.card.image = UIImage(named: randomCardString)


您所做的不是生成随机数,而是以随机顺序显示一组数字。

有一种非常简单的算法(也很快)叫做fisher-yates shuffle。它随机移动一个数组。唯一的缺点是它意味着数组中的任何数字都不能位于它开始的位置。(在你的情况下,这可能是也可能不是一个不利因素)。

无论如何,您应该创建数字数组。1-300然后洗牌。

然后,当您迭代数组时,您将得到一组完整的300个数字,而不需要任何重复,每次都是以随机顺序进行的。

这是我用的密码。(记住现在是凌晨3点,我很累,但我不得不这么做)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import UIKit

var numbers: [Int] = []

for number in 1...52 {
    numbers.append(number)
}

for i in 0..<(numbers.count - 1) {
    let j = Int(arc4random_uniform(UInt32(numbers.count - i))) + i
    swap(&numbers[i], &numbers[j])
}

println(numbers)

也许有一个更整洁的方法来写它。

编辑了功能,因为我的不工作。根据这个答案改编。


在nsmutablerray上添加以下类别(这是修改后的fisher-yates shuffle):

1
2
3
4
5
6
7
- (void) shuffle
{
    for (NSInteger i = [self count] - 1; i > 0; --i)
    {
        [self exchangeObjectAtIndex:arc4random() % (i+1) withObjectAtIndex: i];
    }
}

按顺序生成数字范围(例如1-300),并将其放入NSmutableArray(作为NSnumber)。然后,使用上面的随机播放方法。

然后,从NSmutableArray中按顺序提取结果(索引0-299)。你将随机抽取数字而不替换,我想这就是你想要的。


你要生成这些数字中的一些,还是很多?

如果您只生成了一些,那么您可能需要保留一个已经收到的列表,并在再次收到它们时重试。有点像…

1
2
3
4
5
6
7
8
9
10
NSMutableArray *uniqueNumbers = [[[NSMutableArray alloc] init] autorelease];

...

randomCard = arc4random_uniform(100);
while ([uniqueNumbers containsObject:[NSNumber numberWithInt:randomCard]]) {
    // try again
    randomCard = arc4random_uniform(100);
}
[uniqueNumbers addObject:[NSNumber numberWithInt:r]];

如果你打算用这种方式生成许多随机数,它将变得非常低效。例如,在第99个数字上,你将反复循环,直到随机的机会,你最终得到的两个数字之一还没有在你的列表中。如果您想要生成大量的数字,那么创建一个集合(数组、堆栈等)以及其中所有的数字(1-100)并对其进行无序处理可能会更有效。然后你可以一次把它们从上面弹下来。

1
2
3
4
5
6
7
8
9
10
11
12
NSMutableArray *uniqueNumbers = [[[NSMutableArray alloc] init] autorelease];
// build list
for(int i = 1; i <= 100; i = i + 1)
{
    [uniqueNumbers addObject:[NSNumber numberWithInt:i]];
}
// shuffle list
for(int i = 0; i < 100; i = i + 1)
{
    int n = arc4random() % 100;
    [uniqueNumbers exchangeObjectAtIndex:i withObjectAtIndex:n];
}


xcode 8?斯威夫特3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
extension Array {
    var shuffled: Array {
        var elements = self
        return elements.shuffle()
    }
    @discardableResult
    mutating func shuffle() -> Array {
        indices.dropLast().forEach { a in
            guard case let b = Int(arc4random_uniform(UInt32(count - a))) + a, b != a else { return }
            swap(&self[a], &self[b])
        }
        return self
    }
}

使用

1
2
3
4
5
let numbers = Array(1...100)

let shuffled = numbers.shuffled   // [5, 60, 15, 13, 94, 70, 17, 80, 95, 11, 76, 55, 96, 45, 1, 4, 23, 97, 48, 21, 47, 38, 51, 64, 59, 44, 19, 79, 98, 61, 35, 67, 49, 71, 83, 82, 54, 69, 36, 100, 73, 99, 93, 6, 62, 91, 24, 32, 10, 31, 41, 84, 46, 72, 12, 87, 20, 65, 43, 22, 85, 68, 86, 89, 88, 58, 33, 18, 30, 63, 52, 90, 57, 14, 16, 81, 2, 29, 37, 8, 50, 78, 9, 66, 3, 7, 77, 53, 39, 56, 28, 42, 25, 27, 34, 92, 26, 74, 75, 40]

let get10randomNumbers = numbers.shuffled.prefix(10)   // [71, 23, 33, 48, 73, 81, 75, 18, 19, 67]