У меня есть данные JSON, которые я пытаюсь перебирать, пока ключ не достигнет «teamName», а значение не достигнет команды, которую ввел пользователь. Вот небольшой фрагмент данных JSON, включающий две команды:
{'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'},
Вот что я пробовал до сих пор:
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)
Без оператора else, если я ввожу Bills для userteam, поскольку я уже равен 0, код работает нормально, и вывод:
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'}
Проблема заключается в том, чтобы перебирать данные и останавливаться, как только ключ достигает «teamName», а значение достигает команды, которую ввел пользователь. С помощью оператора else я понял, что функция будет вызывать сама себя, если «teamName» и userteam не будут найдены в первом индексе 0, и будет просто увеличиваться на 1, пока они не будут найдены, но все, что я получаю, это IndexError: индекс списка вне диапазона и Я не знаю, что делать.
Я знаю, что могу просто сделать что-то вроде:
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')
но это кажется нелогичным, учитывая, что полные данные JSON состоят из 32 команд. Я новичок в Python, поэтому не знаю, не упустил ли я какую-нибудь мелкую деталь. Я искал похожие вопросы, но они либо на другом языке, либо только на одном уровне JSON.
Судя по вашему последнему фрагменту кода, вы пытаетесь получить словарь «Защита» по названию команды.
Вы можете сделать что-то вроде этого:
team_name = 'Bills'
defense = None
for team_info in data['body']:
if team_info['teamName'] == team_name:
defense = team_info['teamStats']['Defense']
break
if defense is not None:
print(defense)
else:
print('Team not found')
Я полагаю, вы пытаетесь найти статистику команды по имени команды. Я думаю, что-то вроде ниже будет работать
data = response.json()
userinput_team = input('Enter the team name: \n')
userteam = str(userinput_team)
def defense():
realData = data['body']
for key in realData:
if key['teamName'] == userteam:
userdefense = key['teamStats']['Defense']
print(f"Here are the defensive stats for the {userteam}:\n{userdefense}")
return
print('No Data Found')
defense()
Поскольку вы уже выполняете цикл, я не думаю, что вам нужен этот параметр в функции защиты.
Поскольку вам нужно только первое совпадение, вы можете сделать это в одном выражении, используя 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
)
Что даст вам
{'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'}
если команда найдена, иначе None
.
Я бы предпочел, чтобы вы использовали слово get
в словаре Python, чтобы избежать ошибок в ключах и filter
для соответствия любому совпадающему имени.
Например:
def get_defensive_stats(data, userteam):
# filter to find the team with the matching name
teams = list(filter(lambda team: team.get('teamName') == userteam, data.get('body', [])))
#any team was found and return its defensive stats
if teams:
return teams[0].get('teamStats', {}).get('Defense', {})
else:
return {}
Функция получения слова и фильтра делают код намного чище, спасибо!
Принято, поскольку этот ответ прост, но краток, спасибо!