Dictionaries

I am trying to help a student with her coursework and we are having trouble getting a dictionary to work. We have used print statements to check that there is something in the dictionary and that the data is the correct data type for the key and value and it is but when we try and print the value from the key it prints nil.

It did work for a set of questions which were an array of question structures). Then we filtered these based on a topic(shown below ) and it stopped working

Any help gratefully received!

Here is the code:

mutating func makeGuessForCurrentQuestion(atIndex index:Int) {
        //the answer index is stored in the dictionary data structure against the hash value of the currentQuestion (the question they just answered)
        print(index)
        print(type(of: index))
        print(currentQuestion)
        print(type(of: currentQuestion))
        
        guesses[currentQuestion] = index
        print("From inside Game Model\(guesses)")
        print(guesses[currentQuestion])// Why is this showing nil when there is a value in it??
        if let _ = guesses[currentQuestion]{
            print("Not Nil")
        }else{
            print("Nil")
        }

Here is the code where the values are put into the dictionary:

 var guessWasMade: Bool {
        //if there is a value in the dictionary, then it is true. If is not, then false
        print("From GameViewModel \(game.guesses)")
        
        if let _ = game.guesses[currentQuestion] {
            return true
        } else {
            return false
        }
    }

This is where currentQuestion is coming from:

 var currentQuestion: Question {
        filteredQus[currentQuestionIndex]
        
    }

And filtered questions are being created here

 //FilteredQusAnd10Qus
    private var filteredQus: [Question]{
        var QuizQus: [Question] = []
        var filteredQus: [Question] = []
        filteredQus = questions.filter{$0.topic == "Energy"}
        
        for i in 1...10{
            var randQu = filteredQus.randomElement()//Select a random question
            while QuizQus.contains(randQu!){
                randQu = filteredQus.randomElement()
            }
            QuizQus.append(randQu!)
        }
        return QuizQus
    }

filteredQus is a random selection of ten questions, generated every time it's accessed. I suspect this is not the behaviour you intended, but it is how computed properties work.

currentQuestion is using filteredQus. Thus it's also returning a random question.

Thus why, in makeGuessForCurrentQuestion(atIndex:), you're getting unreliable results - because you're inserting index under the key currentQuestion (which is randomly chosen) and then retrieving a potentially different key (since you call currentQuestion again).

There are many possible ways to change this code to fix the issue, and it's not clear without more context which is best. You could e.g. make filteredQus a lazy var so that it's computed just once and then cached for the lifetime of the object.

2 Likes

Also, tangentially, consider using the random sampling Collection extensions from swift-algorithms, to avoid reinventing that wheel. It also gives you the option to preserve the order (relative to the original collection) if you like.