read out random item from String Array in Swift 3

87 views Asked by At

I have an array of Strings in Swift 3 (Xcode) and I want to read out 5 random unique elements from it. I'm trying something like this:

class ViewController: UIViewController {

    @IBOutlet var Nr1: UILabel!
    @IBOutlet var Nr2: UILabel!
    @IBOutlet var Nr3: UILabel!
    @IBOutlet var Nr4: UILabel!
    @IBOutlet var Nr5: UILabel!

    myArray = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]

    func foo() {
        for index in 0..<6 {
            let randomNr = Int(arc4random_uniform(UInt32(myArray.count)))
            Nr+(index).text = String (randomNr)
        }
    }

}

But I can't take the iteration index as a placeholder to get Nr1.text, Nr2.text, Nr3.text, etc.

And the next question would be: how do I compare the random items so that they are unique?

Can someone help me out with this?

2

There are 2 answers

0
Anthony Cannon On

The way I would do this is to insert them into an arraylist and produce a number between 0 and the size of the list. With this number get and remove that item from the list, and then repeat this process. Each time the size will get smaller and it is impossible to get a non-unique item as you are removing them as you are getting them.

0
Søren Mortensen On

You could try something like the following.

First, add this implementation of a Fisher-Yates shuffle (from here) in order to randomise the elements in the array.

extension MutableCollection {
    /// Shuffles the contents of this collection.
    mutating func shuffle() {
        let c = count
        guard c > 1 else { return }

        for (firstUnshuffled, unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
            let d: IndexDistance = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
            let i = index(firstUnshuffled, offsetBy: d)
            swapAt(firstUnshuffled, i)
        }
    }
}

extension Sequence {
    /// Returns an array with the contents of this sequence, shuffled.
    func shuffled() -> [Element] {
        var result = Array(self)
        result.shuffle()
        return result
    }
}

Then use the shuffled() method to randomise the elements in the array, take the first five elements, and put them into the labels.

class ViewController: UIViewController {

    // ...

    let myArray = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]

    func foo() {
        // Take the array and shuffle it.
        let shuffled = self.myArray.shuffled()
        // Slice the first five elements.
        let randomElements = shuffled[0..<5]

        // Build an array that contains all the labels in order.
        let outlets = [self.nr1, self.nr2, self.nr3, self.nr4, self.nr5]
        // Loop through the randomly chosen elements, together with their indices.
        for (i, randomElement) in randomElements.enumerated() {
            // Put the random element at index `i` into the label at index `i`.
            outlets[i]?.text = randomElement
        }
    }

    // ...

}

What you're trying to do in your question to access each of the IBOutlets in order won't work, because you can't form an identifier from the value inside a variable. However, you can loop through the IBOutlets as shown above.

Additional note: I've changed the names of your UILabel variables from Nr1, Nr2, etc. to nr1, nr2, etc. This is because in Swift, UpperCamelCase should be used only for type names, and variables etc. should be named using lowerCamelCase.