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

Python 通过匹配dict',在列表中查找dict的索引;s值,python,Python,我有一个目录: list = [{'id':'1234','name':'Jason'}, {'id':'2345','name':'Tom'}, {'id':'3456','name':'Art'}] 如何通过匹配name='Tom'有效地找到索引位置[0]、[1]或[2] 如果这是一个一维列表,我可以执行list.index(),但我不知道如何在列表中搜索dict的值 lst = [{'id':'1234','name':'Jason'}, {'id':'2

我有一个目录:

list = [{'id':'1234','name':'Jason'},
        {'id':'2345','name':'Tom'},
        {'id':'3456','name':'Art'}]
如何通过匹配name='Tom'有效地找到索引位置[0]、[1]或[2]

如果这是一个一维列表,我可以执行list.index(),但我不知道如何在列表中搜索dict的值

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
若您需要重复地从name中提取,那个么您应该按name对它们进行索引(使用字典),这样get操作将是O(1)次。一个想法:

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

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

它不会有效率,因为您需要遍历列表,检查其中的每一项(O(n))。如果您想提高效率,可以使用dict of dicts。 关于这个问题,这里有一种可能的方法可以找到它(不过,如果您想坚持这种数据结构,使用生成器实际上更有效,正如Brent Newey在评论中所写;另请参见tokland的回答):


一个简单易读的版本是

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(filter(lambda n: n.get('name') == 'Tom', names)[0])
1
如果您认为可能存在多个匹配项:

[names.index(n) for item in filter(lambda n: n.get('name') == 'Tom', names)]
[1]
对于给定的iterable,生成满足谓词的项的位置

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]
是实现其他有用工具的第三方库。

One liner

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]
>>> [(1, {'id': '2345', 'name': 'Tom'}), (3, {'id': '4567', 'name': 'Tom'})]
我喜欢这种方法的地方在于,通过简单的编辑,您可以获得索引和字典的元组列表。这就是我需要解决的问题,并找到了这些答案。在以下内容中,我在另一个字典中添加了一个重复值,以显示其工作原理:

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]
>>> [(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)

“list”是列表构造函数,最好为列表选择另一个名称(即使在示例中)。如果没有找到元素,响应应该是什么?提出一个例外?返回None?如果您非常需要它,请使用更合适的数据结构(可能是
{'Jason':{'id':'1234'},'Tom':{'id':'1245'},…}
?)@delnan,因为这会导致灾难!如果有的话,它应该是
{'1234':{'name':'Jason'},…}
。这对这个用例没有帮助。你可以通过使用发电机获得你想要的效率。请看tokland的答案。@Brent Newey:生成器并没有改变这样一个事实,即您必须遍历整个列表,并按照aeter的说法进行O(n)搜索。。。根据列表的长度,使用生成器与使用for循环或任何可能是可忽略的区别,而使用dict与使用列表的区别可能是可忽略的not@Brent:你是对的,但是如果搜索的项目在列表的末尾,它能打败字典中的O(1)查找吗?@Dirk the next()当找到匹配项时,对生成器的调用将停止,因此它不必遍历整个列表。@a只要你说得对。我指的是在找到匹配项时能够停止。我认为@Emile的答案没有可读性或Pythonic那么好。因为其目的并不是真的要创建一个生成器(在我看来,使用
next()
),所以目的只是获取索引。此外,这会引发StopIteration,而Python
lst.index()
方法会引发ValueError。@benhoyt:我也不喜欢StopIteration异常,但尽管您可以更改next()的默认值,但它引发的异常是固定的。pythonicity有点主观,所以我不反对它,可能for循环更具pythonic。另一方面,有些人将next()别名为first(),这听起来肯定更好:first(index for(index,d)in…。
first()
听起来确实更好。您可以尝试/排除StopIteration和raise ValueError,以便调用者具有一致性。或者将
next()
的默认值设置为-1。@gdw2:I get
SyntaxError:Generator表达式必须用括号括起来,如果不是唯一的参数的话。@avoliva在next周围加一个括号,如
next((如果d[“name”]=“Tom”),则在enumerate(lst)中为(index,d)加上括号,如果d[“name”=“Tom”),则无)
这似乎是最具可读性和python风格的。它还很好地模仿了
str.find()
的行为。您也可以调用它
index()
,并提出
ValueError
,而不是返回-1(如果这是可取的)。同意-当没有找到匹配项时返回-1,您将始终得到列表中的最后一个dict,这可能不是您想要的。最好返回None并检查调用代码中是否存在匹配项。