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:请参阅我关于使用 listset 的回答 @MAK:有什么不清楚的地方?我知道使用dict 会提供更简洁的访问模式,但我不能。 @Josh:答案仍然是“使用字典”。请参阅我的编辑,了解如何做到这两点。【参考方案2】:

您的访问模式要求使用不同的数据结构(或至少另一种辅助数据结构)。如果您正在使用列表,则在您正在执行的操作时扫描列表实际上是正确的做法,但您不应该使用列表(如果您希望它高效,无论如何)。

如果列表的顺序无关紧要,您应该使用字典(python dict)。如果是这样,您应该使用来自collections 模块的OrderedDict

您还可以使用两个单独的数据结构 - 您已经拥有的列表,另外还有一个 set 仅包含列表中的名称,这样您就可以快速访问测试是否包含。但是,set 并不能帮助您快速访问实际名称数据(您仍然需要在列表中进行线性搜索),因此如果您只是测试包含,它只会是一个有用的模式,但否则总是在插入列表时遍历列表。

编辑:您可能真正想要的是一个列表和一个字典,其中字典是name 和列表中的索引之间的映射。或者,您仍然可以使用dictOrderedDict,但在插入时使用dict.iteritems() 将它们作为数组插入到Mongo 中以创建数组(或看起来像Mongo 的数组)。您可以使用从 zipitertools 中的各种变量来动态构建结果数组中所需的对象。

【讨论】:

请注意 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在列表中查找对象的主要内容,如果未能解决你的问题,请参考以下文章

Python列表操作

使用python查找列表中是不是存在项目的变量

在具有显式键值的对象列表中查找元素

Python中list总结

在Python中按属性获取对象列表中的索引

如何在python列表中查找某个元素的索引