简体   繁体   中英

Swift - Generating random number that is not in retrieved list

I'm trying to retrieve a list from the user defaults, generate a random number that's not in this list, and append this number to the list and save it again.

My function looks like this:

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
}

and this return a list like this:

[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]

as the first list, and for every number being appended, it also adds 3 numbers before this number. Although no number repeats itself, this is not the result I was looking for, therefore I need to know if my function for creating this random number looks wrong.

Any suggestions on how to proceed would be appreciated.

Bear in mind, your user default will persist across runs of your program. Presumably you have (through previous attempts) managed to save a value of that list you give.

Try pasting your code into a fresh Swift console app. It will work correctly for up to 10 runs, then it will go into an infinite loop – because usedNumbersList will contain all 10 numbers possible already – so the while loop will never terminate.

Why you aren't getting the infinite loop in your code but rather the behaviour you describe is a bit mysterious. The cause may be code outside the function you give in your question. But it seems like you need to be able to detect this condition and handle it in some way.

By the way, you would probably find this code easier to debug if you split it into two functions, one that generated random numbers not in a given list:

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
}

This way you can test your random-number-generating function independently (maybe try it out in a playground) from your fetching/saving code:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM