通过匹配 dict 的值,在列表中查找 dict 的索引

我有一系列的措辞:

list = [{'id':'1234','name':'Jason'},
{'id':'2345','name':'Tom'},
{'id':'3456','name':'Art'}]

如何通过匹配 name = ‘ Tom’有效地找到索引位置[0]、[1]或[2] ?

如果这是一个一维列表,我可以执行 list.index () ,但是我不确定如何通过搜索列表中的 dicts 的值来继续。

170032 次浏览
lst = [{'id':'1234','name':'Jason'}, {'id':'2345','name':'Tom'}, {'id':'3456','name':'Art'}]


tom_index = next((index for (index, d) in enumerate(lst) if d["name"] == "Tom"), None)
# 1

如果需要重复从名称中提取,则应该按名称对它们进行索引(使用字典) ,这样 走开操作的时间为 O (1)。一个想法:

def build_dict(seq, key):
return dict((d[key], dict(d, index=index)) for (index, d) in enumerate(seq))


people_by_name = build_dict(lst, key="name")
tom_info = people_by_name.get("Tom")
# {'index': 1, 'id': '2345', 'name': 'Tom'}

它不会有效,因为您需要遍历列表检查其中的每个项(O (n))。如果你想要效率,你可以使用 口头禅。 关于这个问题,这里有一个可能的方法来找到它(尽管,如果你想坚持这个数据结构,它实际上对 使用发电机更有效,正如 Brent Newey 在评论中写的那样; 也可以看 Tokland 的回答) :

>>> L = [{'id':'1234','name':'Jason'},
...         {'id':'2345','name':'Tom'},
...         {'id':'3456','name':'Art'}]
>>> [i for i,_ in enumerate(L) if _['name'] == 'Tom'][0]
1

一个简单的可读版本是

def find(lst, key, value):
for i, dic in enumerate(lst):
if dic[key] == value:
return i
return -1

这里有一个函数,它可以找到字典的索引位置(如果存在的话)。

dicts = [{'id':'1234','name':'Jason'},
{'id':'2345','name':'Tom'},
{'id':'3456','name':'Art'}]


def find_index(dicts, key, value):
class Null: pass
for i, d in enumerate(dicts):
if d.get(key, Null) == value:
return i
else:
raise ValueError('no dict with the key and value combination found')


print find_index(dicts, 'name', 'Tom')
# 1
find_index(dicts, 'name', 'Ensnare')
# ValueError: no dict with the key and value combination found

使用过滤器/索引组合似乎最合乎逻辑:

names=[{}, {'name': 'Tom'},{'name': 'Tony'}]
names.index(next(filter(lambda n: n.get('name') == 'Tom', names)))
1

如果你认为可能有多个匹配:

[names.index(item) for item in filter(lambda n: n.get('name') == 'Tom', names)]
[1]

对于给定的迭代,more_itertools.locate产生满足谓词的项的位置。

import more_itertools as mit




iterable = [
{"id": "1234", "name": "Jason"},
{"id": "2345", "name": "Tom"},
{"id": "3456", "name": "Art"}
]


list(mit.locate(iterable, pred=lambda d: d["name"] == "Tom"))
# [1]

more_itertools 是实现 Itertools 食谱和其他有用工具的第三方库。

一个班轮?

elm = ([i for i in mylist if i['name'] == 'Tom'] or [None])[0]

@ faham 提供的答案是一个很好的一行程序,但它不会将索引返回到包含该值的字典。相反,它返回字典本身。下面是一个简单的获取方法: 如果有多个索引,则获取一个或多个索引列表; 如果没有索引,则获取一个空列表:

list = [{'id':'1234','name':'Jason'},
{'id':'2345','name':'Tom'},
{'id':'3456','name':'Art'}]


[i for i, d in enumerate(list) if 'Tom' in d.values()]

产出:

>>> [1]

我喜欢这种方法的地方在于,通过简单的编辑,您可以获得索引和字典作为元组的列表。这就是我需要解决的问题,并找到了答案。在下面的例子中,我在另一个字典中添加了一个重复的值,以说明它是如何工作的:

list = [{'id':'1234','name':'Jason'},
{'id':'2345','name':'Tom'},
{'id':'3456','name':'Art'},
{'id':'4567','name':'Tom'}]


[(i, d) for i, d in enumerate(list) if 'Tom' in d.values()]

产出:

>>> [(1, {'id': '2345', 'name': 'Tom'}), (3, {'id': '4567', 'name': 'Tom'})]

这个解决方案在所有字典的值中找到包含“ Tom”的字典。

def search(itemID,list):
return[i for i in list if i.itemID==itemID]

我需要一个更通用的解决方案来考虑列表中多个字典具有键值的可能性,以及一个使用列表内涵的简单实现:

dict_indices = [i for i, d in enumerate(dict_list) if d[dict_key] == key_value]

下面将返回第一个匹配项的索引:

['Tom' in i['name'] for i in list].index(True)

我的答案最好用一本字典来回答

food_time_dict = {"Lina": 312400, "Tom": 360054, "Den": 245800}
print(list(food_time_dict.keys()).index("Lina"))

我要求键从字典,然后我翻译列表,如果它没有添加,将有一个错误,然后我使用它作为一个列表。而是在你的代码上:

lists = [{'id': '1234', 'name': 'Jason'},
{'id': '2345', 'name': 'Tom'},
{'id': '3456', 'name': 'Art'}]
    

    

def dict_in_lists_index(lists, search):  # function for convenience
j = 0  # [j][i]
for i in lists:
try:  # try our varible search if not found in list
return f"[{j}][{list(i.values()).index(search)}]"
# small decor
except ValueError: # error was ValueError
pass # aa... what must was what you want to do
j += 1 # not found? ok j++
return "Not Found"
    

    

def dict_cropped_index(lists, search):
for i in lists:
try:
return list(i.values()).index(search)
except ValueError:
pass
return "Not Found"
    

    

print(dict_in_lists_index(lists, 'Tom')) # and end
print(dict_cropped_index(lists, 'Tom')) # now for sure end