Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

How do I randomize Dictionaries instead of Arrays | Swift

I am trying to build a quick app that when a button is hit it returns a random quote with its author, very similar to the fun facts app. The problem that I am facing is the the fun facts app return the element in array format, but I would like to use a Dictionary instead

My current code

struct quoteGroup {

    let quoteDictionary = [
        "Author 1": "Quote 1",
        "Author 2": "Quote 2",
        "Author 3": "Quote 3"
    ]

    func randomQuote() -> DictionaryIndex {
        var unsignedArrayCount = UInt32(quoteDictionary.count)
        var unsignedRandomNumber = arc4random_uniform(unsignedArrayCount)
        var randomNumber = Int(unsignedRandomNumber)

        return quoteDictionary[randomNumber]
    }
}

I tried just changing the return type, but that did not work.

Ozzie

4 Answers

Hi Ozzie,

I haven't tested it but it should work, essentially instead of using a number we grab all the keys in the dictionary first and use the random number to pick a random key from the array returned from the keys property.

Once we have the key when then case it down to a String and use it to fetch the value from the quoteDictionary with the matching key name.

struct QuoteGroup {
    let quoteDictionary = [
        "Author 1": "Quote 1",
        "Author 2": "Quote 2",
        "Author 3": "Quote 3"
    ]

    func randomQuote() -> String {
        var keys = quoteDictionary.keys.array
        var unsignedArrayCount = UInt32(keys.count)
        var unsignedRandomNumber = arc4random_uniform(unsignedArrayCount)
        var randomNumber = Int(unsignedRandomNumber)
        var randomKey = keys[randomNumber] as String

        return quoteDictionary[randomKey]!
    }
}

Hey Chris, thank you for your response! I ran your code in Xcode and it generated a few errors

Errors generated at lines:

func randomQuote() -> DictionaryIndex {

Reference to generic type 'DictionaryIndex' requires arguments in <...>

var keys = quoteDictionary.allKeys as [String]

'[String: String]' does not have a member named 'allKeys'

If I remove "as [String]" the error goes away

Ozzie

Ok, I just had a chance to actually test it and have resolved the errors, it would appear either I misread the Apple docs or just typed out the code too quickly between tasks, either way I've updated the my original post which now has some functioning code.

Also on a side note it's best to always name structs using an uppercase letter followed by camel case which is standard convention these days, so instead of quoteGroup it's better to use QuoteGroup.

Thank you for your help! Also, I will name my structs like that from now on :)

Ozzie

Hey Chris,

I ran into a problem, when the user clicks new quote for example it returns 2 completely different quotes. I understand why this is happening, but I don't know how to fix it.

So for example

  • User taps new quote button
  • Button goes and gets a new random quote from "quoteDictionary"
  • Displays quote and author (Quote 2, Author 2) If that makes sense

The code from my view controller class

class quotes: UIViewController {

    @IBOutlet weak var quoteDisplay: UILabel!
    @IBOutlet weak var authorDisplay: UILabel!

    let quote = QuoteGroup()

    override func viewDidLoad() {
        super.viewDidLoad()
    }


    @IBAction func newQuote() {
        quoteDisplay.text = quote.randomQuote()
        authorDisplay.text = quote.randomQuote()
    }
}

from the struct

struct QuoteGroup {
    let quoteDictionary = [
        "Author 1": "Quote 1",
        "Author 2": "Quote 2",
        "Author 3": "Quote 3",
        "Author 4": "Quote 4",
        "Author 5": "Quote 5",
        "Author 6": "Quote 6"
    ]

    func randomQuote() -> String {
        var keys = quoteDictionary.keys.array
        var unsignedArrayCount = UInt32(keys.count)
        var unsignedRandomNumber = arc4random_uniform(unsignedArrayCount)
        var randomNumber = Int(unsignedRandomNumber)
        var randomKey = keys[randomNumber] as String

        return quoteDictionary[randomKey]!
    }
}

Would this even be possible with swift? or is that not how dictionary's work?

Hey Kirkbyo,

Did you ever figure out how to successfully do this? I'm trying something similar and am running into the same problem. Let me know, thanks!

Yes I did! Here is the solution I am using! (Swift 2)

func randomizeDict(arr: [String: String]) -> [String: String]? {
    let keys: [String] = [String](str.keys.map { $0 }) // Gathers all keys and converts to string
    let randomNumber = Int(arc4random_uniform(UInt32(arr.count))) // Generates random number
    let key: String = keys[randomNumber] // Gets a random key

    guard let value: String = arr[key] else {
        return nil
    }

    return [key: value]
}

Hope this helps!

Yes I did! Here is the solution I am using! (Swift 2)

func randomizeDict(arr: [String: String]) -> [String: String]? {
    let keys: [String] = [String](str.keys.map { $0 }) // Gathers all keys and converts to string
    let randomNumber = Int(arc4random_uniform(UInt32(arr.count))) // Generates random number
    let key: String = keys[randomNumber] // Gets a random key

    guard let value: String = arr[key] else {
        return nil
    }

    return [key: value]
}

Hope this helps!

Awesome! Thanks, this helps a lot!