我有一个字典列表:
list = [{'id':'1234','name':'Jason'},
{'id':'2345','name':'Tom'},
{'id':'3456','name':'Art'}]
我该如何高效地通过匹配名称为'Tom'来查找索引位置[0]、[1]或[2]?
如果这是一个一维列表,我可以使用list.index(),但我不知道如何通过搜索列表中的字典值来继续进行。
我有一个字典列表:
list = [{'id':'1234','name':'Jason'},
{'id':'2345','name':'Tom'},
{'id':'3456','name':'Art'}]
我该如何高效地通过匹配名称为'Tom'来查找索引位置[0]、[1]或[2]?
如果这是一个一维列表,我可以使用list.index(),但我不知道如何通过搜索列表中的字典值来继续进行。
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'}
next()
似乎对我来说很奇怪),目的只是获取索引。此外,这会引发StopIteration,而Python的lst.index()
方法会引发ValueError。 - Ben Hoytnext(index for (index, d) in enumerate(lst) if d["name"] == "Tom", None)
将返回 None
而不是引发异常。 - gdw2next((index for (index, d) in enumerate(lst) if d["name"] == "Tom"), None)
中的 next
周围加上括号,如下所示:(next((index for (index, d) in enumerate(lst) if d["name"] == "Tom"), None))
。 - HussienKd["name"]
这部分改为d.get("name")
,因为在第一种情况下我遇到了KeyError
错误。 - undefined一个简单易读的版本是
def find(lst, key, value):
for i, dic in enumerate(lst):
if dic[key] == value:
return i
return -1
str.find()
的行为。如果喜欢的话,您还可以将其命名为index()
并引发一个ValueError
,而不是返回-1。 - Ben Hoyt如果你需要遍历列表中的每个元素(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
似乎最合理的方法是使用过滤器/索引组合:
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]
@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”的字典及其任何值。
这里有一个函数,如果存在的话,可以找到字典的索引位置。
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
One liner!?
elm = ([i for i in mylist if i['name'] == 'Tom'] or [None])[0]
对于给定的可迭代对象,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 recipes 等其他有用的工具。
我需要一个更通用的解决方案,以考虑列表中有多个字典具有相同键值的可能性。使用列表推导式实现直接明了:
dict_indices = [i for i, d in enumerate(dict_list) if d[dict_key] == key_value]
我的答案更好,使用一个字典就可以了。
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
{ 'Jason': {'id': '1234'}, 'Tom': {'id': '1245'}, ...}
)。 - user395760{'1234': {'name': 'Jason'}, ...}
,但这并不能帮助解决当前的问题。 - OJFord