在字典列表中查找一个项目

5
假设我有一个字典列表,每个字典都有3个元素:名称,id和状态。
list_of_dicts = [{'id':1, 'name':'Alice', 'status':0},{'id':2, 'name':'Bob', 'status':0},{'id':3, 'name':'Robert', 'status':1}]

所以我得到了:
In[20]: print list_of_dicts
Out[20]: 
[{'id': 1, 'name': 'Alice', 'status': 0},
 {'id': 2, 'name': 'Bob', 'status': 0},
 {'id': 3, 'name': 'Robert', 'status': 1}]

如果我收到一个名称,如何在不迭代列表的情况下获取其状态?
例如,我得到了“Robert”,我想输出1。
谢谢。


3
除非你将初始的lod转换成不同的数据结构,否则你无法实现。这本身将需要进行迭代。如果你需要查询多个名称,则这可能仍然是可取的。 - user2390182
1
我不相信你可以在不迭代列表的情况下完成它。如果您必须多次进行搜索,那么将数据结构反转为{'Alice': 0, 'Bob': 0, 'Robert': 1}可能是值得的。然后您只需要迭代一次。 - BoarGules
@BoarGules 同意。如果有重复的名称,您可能需要在查询/键中包含 id - user2390182
也许你应该使用字典的字典(而不是字典的列表),并使用{name}_{id}作为键。 - nick nick
我明白了,那么如果我需要迭代,您会推荐怎样做呢? - Zusman
5个回答

4

没有迭代是无法完成这个操作的。

但是,你可以将你的字典转换为另一种数据结构,例如一个以名称为键的字典:

new_dict = {person["name"]: {k: v for k, v in person.items() if k != "name"} for person in list_of_dicts}

然后你可以这样获取状态:
new_dict["Robert"]["status"]
# 1

此外,正如@tobias_k在评论中提到的那样,您可以保持内部字典不变:

{person["name"]: person for person in list_of_dicts}

以上方法唯一的问题是无法处理多个名称。你可以将唯一标识符添加到键中以区分名称:
new_dict = {(person["name"], person["id"]): person["status"] for person in list_of_dicts}

可以这样调用:

new_dict["Robert", 3]
# 1

尽管创建这些数据结构需要额外的计算(只需一次),但以后的查找将是O(1),而不是每次搜索名称时都要迭代列表。

1
我建议只使用{person["name"]: person for person in list_of_dicts},这样内部字典仍然保持相同的格式(实际上,对于较新版本的Python来说,new_dict.values()几乎与list_of_dicts相同),以便与代码的其他部分兼容。 - tobias_k

4
例如,您可以使用pandas。
import pandas as pd
list_of_dicts = [{'id':1, 'name':'Alice', 'status':0},{'id':2, 'name':'Bob', 'status':0},{'id':3, 'name':'Robert', 'status':1}]

a = pd.DataFrame(list_of_dicts)
a.loc[a['name'] == 'Robert']

使用数据框架进行操作非常快速,因为它是用C++编写的,并且易于操作(就像SQL查询一样)。


这是我会推荐的。另外,可以通过使用自定义类来简化问题。值得庆幸的是,Pandas通过pd.DataFrame提供了这样一个类,因此你不需要重新发明轮子。 - jpp

3

我认为你不能不遍历字典就完成你的要求:
最好的情况是,你会找到有人建议一种可以隐藏迭代的方法。

如果你真正关心的是速度,那么你可以在找到第一个有效结果后立即停止迭代:

for iteration, elements in enumerate(list_of_dicts):
    if elements['name'] == "Robert":
        print "Elements id: ", elements['id']
        break
print "Iterations: ", iteration

# OUTPUT: Elements id: 3, Iterations: 1

请注意,迭代次数可能会有所不同,因为字典没有索引,如果您有更多的“Roberts”,只有一个“id”将被打印。

3

如果你发现需要迭代(除非你能够将数据结构更改为一个封闭的字典),为什么不直接这样做呢?

>>> [d['status'] for d in list_of_dicts if d['name']=='Robert']
[1]

尽管如此,我建议在提出数据结构时,每当您看到一些“id”字段时,请考虑使用地图类型(如dict)。如果有它,您可能希望将其用于通用标识,而不是携带字典。它们也可以用于关系,并且如果以后需要,可以轻松转移到关系数据库中。


2

您的 list_of_dicts 如果没有循环就无法访问,因此为了满足您的需求,您的列表应该进行一些修改,像这样使用1个字典和多个列表

list_of_dicts_modified = {'name':['Alice', 'Bob', 'Robert'],'id':[1, 2, 3], 'status': [0, 0, 1]}
index = list_of_dicts_modified['name'].index(input().strip())
print('Name: {0} ID: {1} Status: {2}'.format(list_of_dicts_modified['name'][index], list_of_dicts_modified['id'][index], list_of_dicts_modified['status'][index]))

输出:

C:\Users\Documents>py test.py
Alice
Name: Alice ID: 1 Status: 0

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