如何在字典列表中进行索引?

3

我是一名初学者。我有一个列表:

players = [{'name': 'John', 'points': '27', 'Played': '6'},
{'name': 'Emil', 'points': '43', 'Played' : '13'},
{'name': 'Susan', 'points': '11', 'Played': '2'},
{'name': 'Peter', 'points': '4', 'Played': '3'}]

我想要做的是能够说:

players["John"]["score"]=newScore
players["john"]["Played"] = players["john"]["Played"]+1

这个列表类似于一个对象列表,其中名称是主键,每个对象都有参数。
但是,当然这样不起作用。例如,我可以通过以下方式触摸元素:
print (players[0]["score"])

那么这将打印出约翰的分数,但使用这种方式,我需要先遍历所有玩家[x]以首先比较名称是否相同,然后才能访问它,这对我来说似乎不太像Python。

你会如何用Pythonic的方式处理这个问题?

5个回答

7
如果“Name”是一个键,那么请更改您的数据结构,方法如下:

players_dict = {d['Name']: d for d in players}

这将使您能够做到以下事情:

players_dict["John"]["score"] = new_score

我的天啊 :) 如果你知道我为了绕过这个问题所花费的时间和丑陋的代码量 - 这种编程语言是如此美丽。我还有一个关于字典和列表的问题,但最好将其作为一个新问题发布。 - MdTp

2
如果您需要通过玩家名称访问这些字典,最好将数据格式调整为符合此需求。
例如:
playersDict = {o['name']: o for o in players}

现在你可以像例子中一样使用playersDict
>>> playersDict['John']['Played']
'6'

1
在我看来,一个字典列表是低效且不推荐的解决方案,用于保存这种结构化数据。你可以使用标准库中的collections.namedtuple,但我更喜欢第三方库pandas,它可以直接接受字典列表。
import pandas as pd

players = [{'name': 'John', 'points': '27', 'Played': '6'},
           {'name': 'Emil', 'points': '43', 'Played' : '13'},
           {'name': 'Susan', 'points': '11', 'Played': '2'},
           {'name': 'Peter', 'points': '4', 'Played': '3'}]

df = pd.DataFrame(players)

print(df)

  Played   name points
0      6   John     27
1     13   Emil     43
2      2  Susan     11
3      3  Peter      4

你可以使用 pandas API 进行操作:
# Add a new column and specify value for a given name
df['Score'] = 0
df.loc[df['name'] == 'John', 'Score'] = 1

# Add 1 to John played
df.loc[df['name'] == 'John', 'Played'] += 1

为什么字典不高效?在这个学习项目中,我最终可能需要的结构是像我在这里描述的字典结构,但在玩家方面,我会附加一个额外的列表或字典,其中包含玩家玩过的所有游戏(加分的游戏),这可能有很多 - 像这样的东西是否应该考虑使用Panda? - MdTp
3
如果一个问题没有标记Pandas,但适合建议使用Pandas时,你可以提出该建议。但请记住,并不是所有人都想要使用或安装Pandas。请确保翻译内容准确无误、通俗易懂,但不要改变原意。 - PM 2Ring
1
@MTdrip,字典列表效率低下,因为需要多层传递;首先遍历每个列表,然后遍历每个字典;接着检查键值对是否已经存在等。如果您不允许使用pandas,请查看这里的其他解决方案。我想说的是,在学习过程中,有比字典列表更好的数据结构可用,例如命名元组。 - jpp
@jpp 谢谢,我会尽可能多地尝试,因为这是学习阶段,如果使用Panda可以使事情更容易并且最终更快,我不排除它,但可能会尝试尽可能遵循标准开始,因为这对我来说仍然是一个新世界,但我绝对迷上了这种语言。 - MdTp
@PM2Ring,虽然我尊重其他人的意见,但我很乐意接受负评。根据我的经验,当问题没有明确说明需要纯Python解决方案时,这是一个有用且有效的解决方案。 - jpp
1
哦,我不会仅仅因为一个答案使用了Pandas或其他第三方库而将其投下反对票,除非当然,这个解决方案比纯Python解决方案更糟糕。;) - PM 2Ring

1
您可以为此创建新的结构化数据。 例如:

>>> new_data_struct_players = {}

>>> for player in players:
...    new_data_struct_players[player['name']] = {
...        'points': int(player['points']),  # make it number (int)
...        'Played': int(player['points'])   # make it number too
...    }

>>> print(new_data_struct_players['John'])
{'points': '27', 'Played': 27}

print(new_data_struct_players['John']['points'])
27

我觉得我理解了这个想法,它可以作为整数使用很不错。但是我想实现动态更新,我正在从文本文件中读取行,当我在文件中遇到"John-Lines"时,我想要更新他的统计信息,如果"John"还没有在列表中,我想要添加他。我不确定,但以上情况似乎需要每次都遍历数据结构?或者如果我向字典中添加一个之前未知的玩家,我是否能够只运行一次? - MdTp

0
你可以使用类来包装当前数据,并提供你指定的专用更新方法,而无需从一开始就改变原始数据的整个结构:
class Row:
   def __init__(self, row):
      self.row = row
   def __setitem__(self, _t, _val):
      self.row[_t] = str(_val)
   def __getitem__(self, _stat):
      return int(self.row[_stat])
   def __repr__(self):
      return '{}({})'.format(self.__class__.__name__, str(self.row))

class Players:
   def __init__(self, data={}):
      self.data = {i['name']:Row(i) for i in data}
   def __getitem__(self, name):
      return self.data[name]
   def __setitem__(self, _name, _data):
      self.data[_name] = Row(_data)
   def __repr__(self):
      return '{}({})'.format(self.__class__.__name__, str(self.data))

players = [{'points': '27', 'name': 'John', 'Played': '6'}, {'points': '43', 'name': 'Emil', 'Played': '13'}, {'points': '11', 'name': 'Susan', 'Played': '2'}, {'points': '4', 'name': 'Peter', 'Played': '3'}]
d = Players(players)
d['John']['points'] = 30
d["John"]["Played"] = d["John"]["Played"]+1
print(d['John'])
d['Bob'] = {'points': '2', 'Played': '5'}

输出:

Row({'points': '30', 'name': 'John', 'Played': '7'})

1
@MTdrip 请查看我的最新编辑。 我在Player中添加了一个__setitem__方法,以便创建新玩家。 - Ajax1234
1
@MTdrip 就像 Ajax 所说的那样。但不幸的是,它不会更新原始的 players 列表,因此当一个新玩家被添加到 d 中时,它就会与 players 不同步。当然,有办法解决这个问题,但事情开始变得复杂了... - PM 2Ring
是的,我刚测试了一下,发现当向“d”添加新玩家时,“players”没有更新——但如果不使用“players”,而是在“d”中全部构建呢?我还不够专业,无法完全看出“players”和“d”之间有什么区别——我正在从飞行中加载玩家,所以我会尝试在这里构建所有内容,并用“d”初始化“players”(如果可能的话)。 - MdTp
我不能用空值初始化它,但我可以使用一个记录将“d”初始化,然后我只需添加到“d”中,这似乎很好地工作 - 它到底在做什么,它正在向我们可以调用的结构添加函数,但它使用的是什么样的列表/字典结构? - MdTp
1
@MTdrip 底层结构仍然是作为类属性存储的字典;但是,该类本身通过利用内置的 __getitem__/__setitem__ 方法提供了略微不同的功能,允许您应用最初提到的数据查找的反向方法。 - Ajax1234
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接