Python在列表中查找对象
Posted
技术标签:
【中文标题】Python在列表中查找对象【英文标题】:Python find object in a list 【发布时间】:2011-07-04 11:20:02 【问题描述】:我有一份人员名单:
[
'name' : 'John', 'wins' : 10 ,
'name' : 'Sally', 'wins' : 0 ,
'name' : 'Fred', 'wins' : 3 ,
'name' : 'Mary', 'wins' : 6
]
我正在使用名称列表 (['Fred', 'Mary', 'Sally']
) 添加胜利。我不知道这个名字是否已经在人员列表中,如果没有,我需要插入一条新记录。目前我正在做以下事情:
name = 'John'
person = None
pidx = None
for p in people_list:
if p['name'] == name:
person = p
pidx = people_list.index(p)
break
if person is None:
person = 'name' : name, 'wins' : 0
person['wins'] += 1
if pidx is None:
people_list.append(person)
else
people_list[pidx] = person
有没有更好的方法来使用列表来做到这一点?鉴于我将其保存到 MongoDB,我不能使用 dict
,因为它将保存为对象,并且我想使用本机数组函数进行排序和映射,这些函数不适用于对象。
【问题讨论】:
【参考方案1】:是的,使用字典。
wins =
for name in winners:
wins.setdefault(name, 0)
wins[name] += 1
编辑:
index =
for name in wins:
person = index.setdefault(name, 'name' : name, 'wins': 0 )
if person['wins'] == 0:
person_list.append(person)
person['wins'] += 1
【讨论】:
我不想使用dict
。我想使用list
。说 "use a dict" 是没用的,因为我希望它是一个列表。我将其保存到 MongoDB,使用 dict 使其成为对象,并且我想使用一些本机数组函数。
@Josh K:请参阅我关于使用 list
和 set
的回答
@MAK:有什么不清楚的地方?我知道使用dict
会提供更简洁的访问模式,但我不能。
@Josh:答案仍然是“使用字典”。请参阅我的编辑,了解如何做到这两点。【参考方案2】:
您的访问模式要求使用不同的数据结构(或至少另一种辅助数据结构)。如果您正在使用列表,则在您正在执行的操作时扫描列表实际上是正确的做法,但您不应该使用列表(如果您希望它高效,无论如何)。
如果列表的顺序无关紧要,您应该使用字典(python dict
)。如果是这样,您应该使用来自collections
模块的OrderedDict
。
您还可以使用两个单独的数据结构 - 您已经拥有的列表,另外还有一个 set
仅包含列表中的名称,这样您就可以快速访问测试是否包含。但是,set
并不能帮助您快速访问实际名称数据(您仍然需要在列表中进行线性搜索),因此如果您只是测试包含,它只会是一个有用的模式,但否则总是在插入列表时遍历列表。
编辑:您可能真正想要的是一个列表和一个字典,其中字典是name
和列表中的索引之间的映射。或者,您仍然可以使用dict
或OrderedDict
,但在插入时使用dict.iteritems()
将它们作为数组插入到Mongo 中以创建数组(或看起来像Mongo 的数组)。您可以使用从 zip
到 itertools
中的各种变量来动态构建结果数组中所需的对象。
【讨论】:
请注意collections.OrderedDict
在 Python 2.7 中是新的,但对于早期版本,OrderedDict
有一个等效的配方。详情请参阅documentation。【参考方案3】:
我在这里假设您不想使用列表以外的任何结构。您的代码应该可以工作,尽管您在更新字典后不必要地将字典写回列表。字典是通过引用复制的,所以一旦你更新它,它就会在列表中保持更新。稍作整理后,您的代码可能如下所示:
def add_win(people_list, name):
person = find_person(people_list, name)
person['wins'] += 1
def find_person(people_list, name):
for person in people_list:
if person['name'] == name:
return person
person = 'name': name, 'wins': 0
people_list.append(person)
return person
【讨论】:
【参考方案4】:如果您不希望 dict 永久使用,请暂时使用。
people = [
'name' : 'John', 'wins' : 10 ,
'name' : 'Sally', 'wins' : 0 ,
'name' : 'Fred', 'wins' : 3 ,
'name' : 'Mary', 'wins' : 6
]
wins = ['Fred', 'Mary', 'Sally']
people_dict = dict((p["name"], p) for p in people)
for winner in wins:
people_dict[winner].setdefault("wins", 0)
people_dict[winner]["wins"] += 1
people = people_dict.values()
【讨论】:
你能把list
转换成dict
吗?我正在从 MongoDB 中提取一个列表。
这正是在定义 people_dict 的行的示例代码中发生的事情。键是名称,值是您拥有的字典。
与列表/字典相互转换的处理开销是多少?
小于每次要在列表中增加一个数字时搜索列表的处理开销。【参考方案5】:
这种特殊情况是由collections.Counter
类型实现的。除了数组生成器,这是一个表达式:
['name':name, 'wins':wins
for name, wins in Counter(names).items()]
如果你想要一个特定的顺序,sorted()
是最简单的方法(这也使用普通的生成器()
,而不是数组生成器[]
,因为它是临时的):
sorted(('name':name, 'wins':wins for name, wins in Counter(names).items()),
key=lambda item: item['name'])
其中item['name']
可以是item['wins']
或任何其他类似的表达式。
【讨论】:
以上是关于Python在列表中查找对象的主要内容,如果未能解决你的问题,请参考以下文章