Home > Mobile >  Looping through a JSON object of unknown length
Looping through a JSON object of unknown length

Time:03-09

I've been trying to figure this one out for hours, to no avail.

response = requests.get("https://api.dictionaryapi.dev/api/v2/entries/en/hello") # public api

Now, the raw response.json() looks like so:

[
    {
        "word": "hello",
        "phonetics": [
            {
                "audio": "https://api.dictionaryapi.dev/media/pronunciations/en/hello-au.mp3",
                "sourceUrl": "https://commons.wikimedia.org/w/index.php?curid=75797336",
                "license": {
                    "name": "BY-SA 4.0",
                    "url": "https://creativecommons.org/licenses/by-sa/4.0"
                }
            },
            {
                "text": "/həˈləʊ/",
                "audio": "https://api.dictionaryapi.dev/media/pronunciations/en/hello-uk.mp3",
                "sourceUrl": "https://commons.wikimedia.org/w/index.php?curid=9021983",
                "license": {
                    "name": "BY 3.0 US",
                    "url": "https://creativecommons.org/licenses/by/3.0/us"
                }
            },
            {
                "text": "/həˈloʊ/",
                "audio": ""
            }
        ],
        "meanings": [
            {
                "partOfSpeech": "noun",
                "definitions": [
                    {
                        "definition": "\"Hello!\" or an equivalent greeting.",
                        "synonyms": [],
                        "antonyms": []
                    }
                ],
                "synonyms": [
                    "greeting"
                ],
                "antonyms": []
            },
            {
                "partOfSpeech": "verb",
                "definitions": [
                    {
                        "definition": "To greet with \"hello\".",
                        "synonyms": [],
                        "antonyms": []
                    }
                ],
                "synonyms": [],
                "antonyms": []
            },
            {
                "partOfSpeech": "interjection",
                "definitions": [
                    {
                        "definition": "A greeting (salutation) said when meeting someone or acknowledging someone’s arrival or presence.",
                        "synonyms": [],
                        "antonyms": [],
                        "example": "Hello, everyone."
                    },
                    {
                        "definition": "A greeting used when answering the telephone.",
                        "synonyms": [],
                        "antonyms": [],
                        "example": "Hello? How may I help you?"
                    },
                    {
                        "definition": "A call for response if it is not clear if anyone is present or listening, or if a telephone conversation may have been disconnected.",
                        "synonyms": [],
                        "antonyms": [],
                        "example": "Hello? Is anyone there?"
                    },
                    {
                        "definition": "Used sarcastically to imply that the person addressed or referred to has done something the speaker or writer considers to be foolish.",
                        "synonyms": [],
                        "antonyms": [],
                        "example": "You just tried to start your car with your cell phone. Hello?"
                    },
                    {
                        "definition": "An expression of puzzlement or discovery.",
                        "synonyms": [],
                        "antonyms": [],
                        "example": "Hello! What’s going on here?"
                    }
                ],
                "synonyms": [],
                "antonyms": [
                    "bye",
                    "goodbye"
                ]
            }
        ],
        "license": {
            "name": "CC BY-SA 3.0",
            "url": "https://creativecommons.org/licenses/by-sa/3.0"
        },
        "sourceUrls": [
            "https://en.wiktionary.org/wiki/hello"
        ]
    }
]

The goal is to return the values of partOfSpeech and definition for however many times they appear in meanings.
In the above case (for the word hello), I'd do:

for i in response.json():
    print(
        f'{i["meanings"][0]["partOfSpeech"]}: {i["meanings"][0]["definitions"][0]["definition"]}\n
        {i["meanings"][1]["partOfSpeech"]}: {i["meanings"][1]["definitions"][0]["definition"]}\n
        {i["meanings"][2]["partOfSpeech"]}: {i["meanings"][2]["definitions"][0]["definition"]}')

This returns:

noun: "Hello!" or an equivalent greeting.
verb: To greet with "hello".
interjection: A greeting (salutation) said when meeting someone or acknowledging someone’s arrival or presence.

However:
a) This is missing 4 more definition values for interjection.
b - and more importantly) for other words, the responses count vary altogether. Obviously this needs the right loop (or perhaps regex) to return correct results for 'any' dictionary API query.
I tried json.loads as well as various key, value loops but all I keep getting are nasty KeyErrors upon TypeErrors.
Please help! Thanks so much!

CodePudding user response:

Use a for loop with good variable names so it's easy to keep track of what you are currently iterating over:

for word_data in json_response:
    for meaning_data in word_data['meanings']:
        print(meaning_data['partOfSpeech'])
        for definition in meaning_data['definitions']:
            print(definition['definition'])

For the input you provided, this outputs:

noun
"Hello!" or an equivalent greeting.
verb
To greet with "hello".
interjection
A greeting (salutation) said when meeting someone or acknowledging someone’s arrival or presence.
A greeting used when answering the telephone.
A call for response if it is not clear if anyone is present or listening, or if a telephone conversation may have been disconnected.
Used sarcastically to imply that the person addressed or referred to has done something the speaker or writer considers to be foolish.
An expression of puzzlement or discovery.

Of course we can make it a bit nicer, for example:

for word_data in json_response:
    for meaning_data in word_data['meanings']:
        print(f"Part of speech: {meaning_data['partOfSpeech']}\n\nDefinitions: "
              f"{', '.join(definition['definition'] for definition in meaning_data['definitions'])}")

outputs

Part of speech: noun

Definitions:"Hello!" or an equivalent greeting.
Part of speech: verb

Definitions:To greet with "hello".
Part of speech: interjection

Definitions:A greeting (salutation) said when meeting someone or acknowledging someone’s arrival or presence., A greeting used when answering the telephone., A call for response if it is not clear if anyone is present or listening, or if a telephone conversation may have been disconnected., Used sarcastically to imply that the person addressed or referred to has done something the speaker or writer considers to be foolish., An expression of puzzlement or discovery.

CodePudding user response:

Easy way using nested for loops:

import requests

response = requests.get("https://api.dictionaryapi.dev/api/v2/entries/en/hello") # public api
meanings = response.json()[0]['meanings']

for x in meanings:
    print(x['partOfSpeech'])

    
    for y in x['definitions']:
        print(y['definition'])

output:
noun
"Hello!" or an equivalent greeting.
verb
To greet with "hello".
interjection
A greeting (salutation) said when meeting someone or acknowledging someone’s arrival or presence. A greeting used when answering the telephone. A call for response if it is not clear if anyone is present or listening, or if a telephone conversation may have been disconnected. Used sarcastically to imply that the person addressed or referred to has done something the speaker or writer considers to be foolish. An expression of puzzlement or discovery.

CodePudding user response:

As an alternative to explicit looping, the matcho package* allows you to write the rules to extract the data declaratively:

from matcho import build_matcher, build_template, bind, insert


matcher = build_matcher(
    [{
      'word': bind('word'),
      'meanings': [
          {
              'partOfSpeech': bind('part_of_speech'),
              'definitions': [{'definition': bind('definition')}, ...]
          }, 
          ...
      ]
    }]
)

The pattern passed to build_matcher resemples the structure of the (json) data, where bind('name') specifies which values to extract and ... declares repeating list elements of arbitrary length.

After matching the data, you can inspect the bindings directly or use them in a template to construct a different data structure for further use.

bindings = matcher(response.json())

template = build_template(
    [[insert("word"), insert("part_of_speech"), insert("definition")], 
     ..., 
     ...]
)

for word, part, definition in template(bindings):
    print(f"{word} ({part}): {definition}")

Output:

hello (noun): "Hello!" or an equivalent greeting.
hello (verb): To greet with "hello".
hello (interjection): A greeting (salutation) said when meeting someone or acknowledging someone’s arrival or presence.
hello (interjection): A greeting used when answering the telephone.
hello (interjection): A call for response if it is not clear if anyone is present or listening, or if a telephone conversation may have been disconnected.
hello (interjection): Used sarcastically to imply that the person addressed or referred to has done something the speaker or writer considers to be foolish.
hello (interjection): An expression of puzzlement or discovery.

*full disclosure: written by me, still lacking proper documentation

  • Related