pythonjsonrecursion

Trying to iterate through JSON data to match user input


I have JSON data that I'm trying to iterate over until the key reaches 'teamName' and the value reaches the team the user inputted. Here's a small section of the JSON data that includes 2 teams:

{'body': [{'conference': 'American Football Conference',
           'conferenceAbv': 'AFC',
           'currentStreak': {'length': '0', 'result': ''},
           'division': 'East',
           'espnLogo1': 'https://a.espncdn.com/combiner/i?img=/i/teamlogos/nfl/500/buf.png',
           'loss': '0',
           'nflComLogo1': 'https://res.cloudinary.com/nflleague/image/private/f_auto/league/giphcy6ie9mxbnldntsf',
           'pa': '0',
           'pf': '0',
           'teamAbv': 'BUF',
           'teamCity': 'Buffalo',
           'teamID': '4',
           'teamName': 'Bills',
           'teamStats': {'Defense': {'defTD': '3',
                                     'defensiveInterceptions': '18',
                                     'fumbles': '20',
                                     'fumblesLost': '10',
                                     'fumblesRecovered': '19',
                                     'passDeflections': '79',
                                     'passingTDAllowed': '18',
                                     'passingYardsAllowed': '3342',
                                     'qbHits': '117',
                                     'rushingTDAllowed': '14',
                                     'rushingYardsAllowed': '1880',
                                     'sacks': '54',
                                     'soloTackles': '719',
                                     'tfl': '86',
                                     'totalTackles': '1054'},
                         'Kicking': {'fgAttempts': '29',
                                     'fgMade': '24',
                                     'fgYds': '0',
                                     'kickYards': '0',
                                     'xpAttempts': '50',
                                     'xpMade': '49'},
                         'Passing': {'int': '18',
                                     'passAttempts': '579',
                                     'passCompletions': '385',
                                     'passTD': '29',
                                     'passYds': '4306'},
                         'Punting': {'puntTouchBacks': '3',
                                     'puntYds': '2334',
                                     'punts': '51',
                                     'puntsin20': '24'},
                         'Receiving': {'recTD': '29',
                                       'recYds': '4306',
                                       'receptions': '385',
                                       'targets': '545'},
                         'Rushing': {'carries': '512',
                                     'rushTD': '22',
                                     'rushYds': '2212'}},
           'tie': '0',
           'wins': '0'},
          {'conference': 'American Football Conference',
           'conferenceAbv': 'AFC',
           'currentStreak': {'length': '0', 'result': ''},
           'division': 'East',
           'espnLogo1': 'https://a.espncdn.com/combiner/i?img=/i/teamlogos/nfl/500/mia.png',
           'loss': '0',
           'nflComLogo1': 'https://res.cloudinary.com/nflleague/image/private/f_auto/league/lits6p8ycthy9to70bnt',
           'pa': '0',
           'pf': '0',
           'teamAbv': 'MIA',
           'teamCity': 'Miami',
           'teamID': '20',
           'teamName': 'Dolphins',
           'teamStats': {'Defense': {'defTD': '4',
                                     'defensiveInterceptions': '15',
                                     'fumbles': '24',
                                     'fumblesLost': '10',
                                     'fumblesRecovered': '25',
                                     'passDeflections': '81',
                                     'passingTDAllowed': '27',
                                     'passingYardsAllowed': '3761',
                                     'qbHits': '140',
                                     'rushingTDAllowed': '15',
                                     'rushingYardsAllowed': '1650',
                                     'sacks': '56',
                                     'soloTackles': '711',
                                     'tfl': '79',
                                     'totalTackles': '1088'},
                         'Kicking': {'fgAttempts': '28',
                                     'fgMade': '24',
                                     'fgYds': '0',
                                     'kickYards': '0',
                                     'xpAttempts': '59',
                                     'xpMade': '58'},
                         'Passing': {'int': '15',
                                     'passAttempts': '566',
                                     'passCompletions': '393',
                                     'passTD': '30',
                                     'passYds': '4698'},
                         'Punting': {'puntTouchBacks': '3',
                                     'puntYds': '2424',
                                     'punts': '53',
                                     'puntsin20': '20'},
                         'Receiving': {'recTD': '30',
                                       'recYds': '4698',
                                       'receptions': '393',
                                       'targets': '549'},
                         'Rushing': {'carries': '456',
                                     'rushTD': '27',
                                     'rushYds': '2308'}},
           'tie': '0',
           'wins': '0'},

Here's what I've tried so far:

data = response.json()

userinput_team = input('Enter the team name')
userteam = str(userinput_team)

def defense(i):
    for key in data["body"][i]:
        value = data["body"][i][key]
        if key == 'teamName' and value == userteam:
            userdefense = data['body'][i]['teamStats']['Defense']
            print(f"Here are the defensive stats for the {value}:\n{userdefense}")
            return
        else:
            return defense(i+1)
        
        
defense(0)

Without the else statement if I input Bills for userteam, since i is already 0 the code works fine and the output is:

Here are the defensive stats for the Bills:
{'fumblesLost': '10', 'defTD': '3', 'fumbles': '20', 'fumblesRecovered': '19', 'soloTackles': '719', 'qbHits': '117', 'passingTDAllowed': '18', 'passDeflections': '79', 'passingYardsAllowed': '3342', 'totalTackles': '1054', 'defensiveInterceptions': '18', 'tfl': '86', 'rushingYardsAllowed': '1880', 'sacks': '54', 'rushingTDAllowed': '14'}

The problem is iterating through the data and stopping once the key reaches 'teamName' and the value reaches the team the user inputted. I figured with the else statement that the function would call itself if 'teamName' and userteam weren't found in the first index 0 and would just increment by 1 until they were found but all I get is IndexError: list index out of range and I'm not sure what to do.

I know I can just do something like:


data = response.json()

userinput_team = input('Enter the team name')
userteam = str(userinput_team)

Bills = 0
Dolphins = 1

userdefense_Bills = data['body'][Bills]['teamStats']['Defense']
userdefense_Dolphins = data['body'][Dolphins]['teamStats']['Defense']

if userteam == 'Bills':
    print(userdefense_Bills)
elif userteam == 'Dolphins':
    print(userdefense_Dolphins)
else:
    print('Team not found')

but this just seems counterintuitive considering the full JSON data consists of 32 total teams. I'm new to Python so I don't know if I'm missing some small detail. I've searched for similar questions but they're either in a different language or only on one level JSON.


Solution

  • Since you just need the first match, you can do this in a single expression using next():

    userinput_team = 'Bills'
    
    team_defense = next(
        (
            item['teamStats']['Defense'] 
            for item in data['body'] 
            if item['teamName'] == userinput_team
        ), 
        None. # <- this can be any default value you want for unknown team
    )
    

    Which will give you

    {'defTD': '3',
     'defensiveInterceptions': '18',
     'fumbles': '20',
     'fumblesLost': '10',
     'fumblesRecovered': '19',
     'passDeflections': '79',
     'passingTDAllowed': '18',
     'passingYardsAllowed': '3342',
     'qbHits': '117',
     'rushingTDAllowed': '14',
     'rushingYardsAllowed': '1880',
     'sacks': '54',
     'soloTackles': '719',
     'tfl': '86',
     'totalTackles': '1054'}
    

    if the team is found, otherwise None.