如何遍历嵌套字典(在嵌套列表中)并将值复制到新列表中

How can I iterate through a nested dictionary (withnin a nested list) and copy the values into a new list

我正在尝试对一组电子竞技游戏数据进行一些数据分析。数据格式如下(由json转换而来):

game_data = [{"match_id":1, "players":[{"player_name":"Tom", "won":True},
                                       {"player_name":"Anna", "won":False}]}, 
             {"match_id":2, "players":[{"player_name":"Tom", "won":False},
                                       {"player_name":"Fred", "won":True}]}]

我想获取玩家“Tom”的列表,其中包含他的输赢。像这样:

tom_won = [True, False]

到目前为止我已经尝试过的方法(见下文)没有奏效,所以我希望你们中的一个人能够向我展示更好的方法。

index = 0
tom_won = []

while index < len(game_data)
   for game_data[index]["players"][0]["won"] in data[index]:
      if game_data[index]["players"][0]["player_name"] == "Tom":
         tom_won.append(game_data[index]["players"][0]["won"])

   for game_data[index]["players"][1]["won"] in data[index]:
      if game_data[index]["players"][1]["player_name"] == "Tom":
         tom_won.append(game_data[index]["players"][1]["won"])
   index += 1

给你:

res = []
for game in game_data:
    for player in game['players']:
        if player['player_name'] == 'Tom':
            res.append(player['won'])
print(res)

输出:

[True, False]

您需要遵循您的结构:

  • 迭代外部数组中的匹配元素
  • 对于每个数组,从键 'players'
  • 给定的数组中迭代玩家
  • 为每个玩家检查姓名,并检索 name 如果它是您正在寻找的玩家。
def get_won(data, name):
    result = []
    for match in data:
        for player in match['players']:
            if player['player_name'] == name:
                result.append(player['won'])
  return result

print(get_won(game_data, 'Tom'))  # [True, False]
print(get_won(game_data, 'Fred')) # [True]
print(get_won(game_data, 'Anna')) # [False]                                   

List-comprehension版本

def get_won(data, name):
    return [player['won'] for match in data for player in match['players'] 
                                            if player['player_name'] == name]

这是一种通过列表理解来做到这一点的方法:

all_players = [p for m in game_data for p in m['players']]
tom = [m["won"] for m in all_players if m['player_name'] == "Tom"]

结果 [True, False]

试试这个:

game_data = [{"match_id":1, "players":[{"player_name":"Tom", "won":True},
                                       {"player_name":"Anna", "won":False}]}, 
             {"match_id":2, "players":[{"player_name":"Tom", "won":False},
                                       {"player_name":"Fred", "won":True}]}]


tom_won = []

for each_match in game_data:
    for each_player in each_match["players"]:
        player_name = each_player["player_name"]
        if player_name == "Tom":
            tom_won.append(each_player["won"])

此外,您可以使用 defaultdict:

获取所有玩家的成绩
game_data = [{"match_id":1, "players":[{"player_name":"Tom", "won":True},
                                       {"player_name":"Anna", "won":False}]}, 
             {"match_id":2, "players":[{"player_name":"Tom", "won":False},
                                       {"player_name":"Fred", "won":True}]}]


import collections

player_won = collections.defaultdict(list)
for each_match in game_data:
    for each_player in each_match["players"]:
        player_name = each_player["player_name"]
        player_won[player_name].append(each_player["won"])

我正在使用 python2.7,但代码应该很容易更改为 运行 in python3.

我建议先研究数据结构,例如:

game_data = [
    {"match_id": 1, "results": {"Tom": True, "Anna": False}}, 
    {"match_id": 2, "results": {"Tom": False, "Fred": True}}
]

然后您可以使用它来生成一位玩家的摘要:

>>> [match['results']['Tom'] for match in game_data]
[True, False]

这是 not a really good data structure,但至少更容易使用。

won:

之间增加一点连贯性也是有意义的
game_data = [
    {"match_id": 1, "winner": 1, "player_names": ["Anna", "Tom"]}, 
    {"match_id": 2, "winner": 0, "player_names": ["Fred", "Tom"]}, 
]

然后:

def results(match, name):
    return match['player_names'][match['winner']] == name

player_results = [results(match, 'Tom') for match in game_data]

为避免名称重复,您也可以使用玩家标识符:

from collections import namedtuple

Game = namedtuple('Game', ['match_id', 'winner', 'players'])

game_data = [
    Game(match_id=1, winner=1, players=[0, 1]),
    Game(match_id=2, winner=2, players=[1, 2]),
]

player_id = {name: i for i, name in enumerate(['Anna', 'Tom', 'Fred'])}


player_results = [game.winner == player_id['Tom'] for game in game_data]

您是唯一能够真正回答“什么是最好的数据结构”这个问题的人,但我希望这对您有所帮助。

另请注意,您可以简单地过滤结果以仅显示玩家参加的比赛,例如最后一个数据结构:

[game.winner == player_id['Fred'] for game in game_data if player_id['Fred'] in game.players]

这不是最简洁的形式,但您可以使用迭代器首先获取玩家参与的游戏,然后获取结果:

def player_games(games, name):
    return (game for game in game_data if player_id[name] in game.players)

[game.winner == player_id['Fred'] for game in player_games(game_data, 'Fred')]