【问题标题】:Swift - Generating random number that is not in retrieved listSwift - 生成不在检索列表中的随机数
【发布时间】:2015-03-07 05:41:45
【问题描述】:

我正在尝试从用户默认值中检索一个列表,生成一个不在此列表中的随机数,然后将此数字附加到列表中并再次保存。

我的函数如下所示:

func createRandiAndSaveNumberToCell()->Double{

    var defaults = NSUserDefaults.standardUserDefaults()

    var numbersList: [Int] = []

    if let firstNameIsNotNill = defaults.objectForKey("usedNumbersList") as? [Int] {
        numbersList = defaults.objectForKey("usedNumbersList") as [Int]
    }

    var randomNumb = Int(arc4random_uniform(10))

    while contains(numbersList, randomNumb){
        randomNumb = Int(arc4random_uniform(10))
    }
    numbersList.append(randomNumb)
    defaults.setObject(numbersList, forKey: "usedNumbersList")

    var randi = Double(randomNumb)
    println(numbersList)

 return randi
}

这会返回一个这样的列表:

[13, 26, 75, 35, 57, 23, 6, 0, 74, 69, 38, 30, 3, 29, 52, 62, 46, 42, 37, 55, 65, 9, 18, 49, 15, 40, 71, 20, 44, 67, 43, 21, 33, 59, 8, 1, 63, 68, 2, 5]

作为第一个列表,对于每个附加的数字,它还会在该数字之前添加 3 个数字。 虽然没有数字重复,但这不是我想要的结果,因此我需要知道我创建这个随机数的函数是否看起来错误。

任何关于如何进行的建议将不胜感激。

【问题讨论】:

  • 你测试过这个功能吗?这似乎是查看它是否有效的最简单方法:P 此外,看起来您做得正确。只需使用 while 循环并继续生成数字,直到您得到一个不在列表中的数字。我想这就是你的意思。
  • 请多解释一下“在这个数字前加3个数字”,这没有意义。此外,正如所写的那样,这段代码并不算太远,尽管它可以进行一些优化。最大的问题是您只选择了 0 到 9 之间的随机数,而您返回的列表中的数字要高得多。一旦你调用这个函数 11 次,你就会陷入无限循环。
  • 用字典代替数组。它的键是唯一的,你可以测试一个键是否已经存在。

标签: ios xcode swift nsuserdefaults contains


【解决方案1】:

请记住,您的用户默认设置将在您的程序运行期间保持不变。大概您(通过以前的尝试)设法保存了您提供的列表的值。

尝试将您的代码粘贴到新的 Swift 控制台应用中。它最多可以运行 10 次,然后进入无限循环——因为usedNumbersList 已经包含所有可能的 10 个数字——所以 while 循环永远不会终止。

为什么您的代码中没有出现无限循环,而是您描述的行为有点神秘。原因可能是您在问题中提供的函数之外的代码。但您似乎需要能够检测到这种情况并以某种方式处理它。

顺便说一句,如果将这段代码拆分为两个函数,一个生成不在给定列表中的随机数的函数,您可能会发现它更易于调试:

func randomNotIn(source: [Int], #upperBound: UInt32) -> Int {
    // detect possible infinte loop
    precondition(source.count < Int(upperBound))

    // by making this a do…while, you can scrap the double-assignment:
    var candidate: Int   // you don’t _have_ to give a var a value
    do {
        // so long as the compiler can see it’s guaranteed to be 
        // assigned a value before it’s first used
        candidate = Int(arc4random_uniform(upperBound))
    } while contains(source, candidate)

    return candidate
}

这样你就可以从你的获取/保存代码中独立地测试你的随机数生成函数(也许在操场上尝试一下):

func createRandiAndSaveNumberToCell() -> Double {

    let defaults = NSUserDefaults.standardUserDefaults()
    let usedKeyName = "usedNumbersList"

    // this is an alternative to your if-let, which uses the “??” operator
    // to supply an empty list when objectForKey returns nil:
    let usedNumbersList = defaults.objectForKey(usedKeyName) as? [Int] ?? []

    let newRandom = randomNotIn(usedNumbersList, upperBound: 10)

    let newUsedNumbersList = usedNumbersList + [newRandom]

    defaults.setObject(newUsedNumbersList, forKey: usedKeyName)

    println(newUsedNumbersList)

    return Double(newRandom)
}

【讨论】:

  • 我以与旧代码完全相同的方式实现了您提供的代码,但您的代码运行良好。感谢您的贡献,现在我将弄清楚为什么原始代码不起作用! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-23
  • 2021-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多