Python在列表中查找对象

时间:2011-02-25 17:16:45

标签: python list search indexing

我有一份人员名单:

[
    {'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,因为它将保存为对象,我想使用本机数组函数进行对象不可用的排序和映射。

5 个答案:

答案 0 :(得分:12)

我在这里假设你不想使用除列表之外的任何结构。您的代码应该可以工作,尽管您在更新后不必要地将字典写回列表。字典是通过引用复制的,因此一旦更新它,它就会在列表中保持更新状态。稍微整理一下后,您的代码可能如下所示:

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

答案 1 :(得分:8)

是的,请使用词典。

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

答案 2 :(得分:5)

如果您不希望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()

答案 3 :(得分:3)

您的访问模式规定使用不同的数据结构(或至少另一个辅助数据结构)。正如你正在使用列表一样,扫描列表实际上是正确的做法,但你不应该使用列表(如果你希望它有效,无论如何)。

如果列表的顺序无关紧要,则应使用Dictionary(python dict)。如果是,则应使用OrderedDict模块中的collections

您还可以使用两个单独的数据结构 - 您已有的列表,另外还有set只包含列表中的名称,以便您可以快速访问测试包含。但是,set无法帮助您快速访问实际名称数据(您仍然需要在列表中进行线性搜索),所以如果您只是在测试它,它将只是一个有用的模式包含,但在插入列表时总是走在列表中。

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

答案 4 :(得分:0)

此特定情况由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']或其他任何可比较的表达。