0

I have been trying to write a program that would randomly select a question from a list of questions and then display the question itself. The information is stored in a .json file.

Here is my current code:

import json
import random

with open("C:\\LearningArabic\\LiblibArriby\\Lessons\\L1_Letters\\L1_Letters.json", "r", encoding = "utf-8-sig") as read_file:
    data = json.load(read_file)

t = data["letters"]["part one"]["meem"]["questions"]
print(t) #This prints all of the necessary information. Not actually necessary but it helps me know that this section of code is working
print("")
print(t.get(random.choice(("question"))))
print("")

Eventually I'll build it out more but right now this is just to get the idea working.

Here is my .json file:

{"letters":
        {"part one": {
                "meem": {
                        "questions": {
                                "question": "What sound does 'م' make?",
                                "arabic": "م",
                                "transliteration": "m",
                                "english": "m",
                                "answer": "m",
                                "wronganswer" : ["a", "b", "kh", "ta", "da", "du", 

"ee", "yeh", "he", "ha", "l", "n", "f"]},
                        "questions": {
                                "question": "What letters are in the word 'وز'?",   

                                "arabic": "موز",
                                "transliteration": "mooz",
                                "english": "banana",
                                "answer": "م و ز",
                                "wronganswer": [
                                        "ه و ز",
                                        "ه و ر", 
                                        "م ف ز",
                                        "م و ر",
                                        "ه ف ر"]},
                        "questions": {
                                "question": "What word do the letters 'ه ر م' make",    

                                "arabic": "ه ر م",
                                "transliteration": "haram",
                                "english": "pyramid",
                                "answer": "هرم",
                                "wronganswer": [
                                        "مرم", 
                                        "هزم", 
                                        "موم",
                                        "مرع",
                                        "هبم"]}
                        }
                }}
 }

When I run the code the I get the following:

{'question': "What word do the letters 'ه ر م' make", 'arabic': 'ه ر م', 'transliteration': 'haram', 'english': 'pyramid', 'answer': 'هرم', 'wronganswer': ['مرم', 'هزم', 'موم', 'مرع', 'هبم']}

None

Main Question:

When I print(t) I think I should be getting a printout of all of the questions. Instead, I'm only getting a printout of the last question. And when I try and print a random question, I get the result of "None" which I don't understand. My lists are all populated, why is python unable to find anything? My main goal is to learn how to select random values from a json file - if my json file format needs to be updated please let me know.

Jack Duane
  • 185
  • 3
  • 17
  • Possible duplicate of [json.loads allows duplicate keys in a dictionary, overwriting the first value](https://stackoverflow.com/questions/14902299/json-loads-allows-duplicate-keys-in-a-dictionary-overwriting-the-first-value) – toti08 Oct 04 '18 at 11:22
  • This has to do with `json` allowing duplicate keys, but once this is translated into a dictionary the duplicate keys are overwritten, hence only the last one is kept. – toti08 Oct 04 '18 at 11:23
  • You don't have lists of questions there. – Stop harming Monica Oct 04 '18 at 11:26
  • @toti08, how is this a duplicate question? Though some of the python mechanics might be similar (like how I've inadequately structured my .json file), our questions are asking for two different things. There is nothing about making random selections in the other question (which is my main point) and if you wanted to learn how to randomly select elements the other question would be of little help - especially for a python beginner like myself. If I need to restructure my .json file then perhaps this question could help show others the same thing. – Jack Duane Oct 04 '18 at 12:11
  • @JackDuane you said you were not able to print all the questions and that's because of the duplicate sections in your `json` file. Once you fix that problem selecting a random question is a totally different problem that has nothing to do with json, but I think the key is fixing the duplicate keys. – toti08 Oct 04 '18 at 12:16
  • @toti08, I see your point. I had played around with the .json file in a few different formats (some with unique sections such as question1, question2, etc.) but I ended up thinking that the duplicates would make it easier to select a random file. I suppose I was mistaken, thanks for highlighting the need for unique sections toti08! – Jack Duane Oct 04 '18 at 12:19

2 Answers2

2

We can't say that the JSON is invalid but you should avoid having similar key names (questions in your example)

RFC 7159 explains why unique names (keys) are good:

An object whose names are all unique is interoperable in the sense that all software implementations receiving that object will agree on the name-value mappings. When the names within an object are not unique, the behavior of software that receives such an object is unpredictable. Many implementations report the last name/value pair only. Other implementations report an error or fail to parse the object, and some implementations report all of the name/value pairs, including duplicates.

JSON parsing libraries have been observed to differ as to whether or not they make the ordering of object members visible to calling software. Implementations whose behavior does not depend on member ordering will be interoperable in the sense that they will not be affected by these differences.

You can try converting your JSON into the given format:

{
  "letters": {
    "part one": {
      "meem": {
        "questions": [
          {
            "question": "What sound does 'م' make?",
            "arabic": "م",
            "transliteration": "m",
            "english": "m",
            "answer": "m",
            "wronganswer": [
              "a",
              "b",
              "kh",
              "ta",
              "da",
              "du",
              "ee",
              "yeh",
              "he",
              "ha",
              "l",
              "n",
              "f"
            ]
          },
          {
            "question": "What letters are in the word 'وز'?",
            "arabic": "موز",
            "transliteration": "mooz",
            "english": "banana",
            "answer": "م و ز",
            "wronganswer": [
              "ه و ز",
              "ه و ر",
              "م ف ز",
              "م و ر",
              "ه ف ر"
            ]
          },
          {
            "question": "What word do the letters 'ه ر م' make",
            "arabic": "ه ر م",
            "transliteration": "haram",
            "english": "pyramid",
            "answer": "هرم",
            "wronganswer": [
              "مرم",
              "هزم",
              "موم",
              "مرع",
              "هبم"
            ]
          }
        ]
      }
    }
  }
}

Then you can do something like this to fetch a random question from the list of questions:

import json
from random import randint


def random_question():
    with open('result.json') as fp:
        data = json.load(fp)
        questions = data["letters"]["part one"]["meem"]["questions"]
        random_index = randint(0, len(questions)-1)
        return questions[random_index]['question']

print(random_question())

output What sound does 'م' make? or What letters are in the word 'وز'?

toti08
  • 2,448
  • 5
  • 24
  • 36
Abhi
  • 442
  • 1
  • 10
  • 24
2

Since your JSON structure contains multiple entries of the same key, you should use a custom JSON decoder that resolves key conflicts by turning values of the same key into a list:

from json import JSONDecoder

def parse_object_pairs(pairs):
    d = {}
    converted_keys = set()
    for key, value in pairs:
        if key not in d:
            d[key] = value
        elif key in converted_keys:
            d[key].append(value)
        else:
            d[key] = [d[key], value]
            converted_keys.add(key)
    return d

decoder = JSONDecoder(object_pairs_hook=parse_object_pairs)
data = decoder.decode(read_file.read())

so that the questions key in data becomes a list of dicts:

{'letters': {'part one': {'meem': {'questions': [{'answer': 'm',
                                                  'arabic': 'م',
                                                  'english': 'm',
                                                  'question': 'What sound does '
                                                              "'م' make?",
                                                  'transliteration': 'm',
                                                  'wronganswer': ['a',
                                                                  'b',
                                                                  'kh',
                                                                  'ta',
                                                                  'da',
                                                                  'du',
                                                                  'ee',
                                                                  'yeh',
                                                                  'he',
                                                                  'ha',
                                                                  'l',
                                                                  'n',
                                                                  'f']},
                                                 {'answer': 'م و ز',
                                                  'arabic': 'موز',
                                                  'english': 'banana',
                                                  'question': 'What letters '
                                                              'are in the word '
                                                              "'وز'?",
                                                  'transliteration': 'mooz',
                                                  'wronganswer': ['ه و ز',
                                                                  'ه و ر',
                                                                  'م ف ز',
                                                                  'م و ر',
                                                                  'ه ف ر']},
                                                 {'answer': 'هرم',
                                                  'arabic': 'ه ر م',
                                                  'english': 'pyramid',
                                                  'question': 'What word do '
                                                              "the letters 'ه "
                                                              "ر م' make",
                                                  'transliteration': 'haram',
                                                  'wronganswer': ['مرم',
                                                                  'هزم',
                                                                  'موم',
                                                                  'مرع',
                                                                  'هبم']}]}}}}

so that you can easily use random.choice on the list to pick a question for output:

print(random.choice(data['letters']["part one"]["meem"]["questions"]))

This outputs (randomly):

{'question': "What sound does 'م' make?", 'arabic': 'م', 'transliteration': 'm', 'english': 'm', 'answer': 'm', 'wronganswer': ['a', 'b', 'kh', 'ta', 'da', 'du', 'ee', 'yeh', 'he', 'ha', 'l', 'n', 'f']}
blhsing
  • 91,368
  • 6
  • 71
  • 106
  • 1
    Not sure why you think I missed the second half of your question since I already showed you how to print a randomly picked question dict with `random.choice(data['letters']["part one"]["meem"]["questions"])`. Printing the question itself then becomes trivial by simply accessing the `question` key of the dict. – blhsing Oct 04 '18 at 12:55
  • 1
    I apologize. I was on my way out the door for work and I didn't catch that. – Jack Duane Oct 04 '18 at 15:32