问题:通过匹配字典的值来找到列表中字典的索引
我有一些字典:
list = [{'id':'1234','name':'Jason'},
{'id':'2345','name':'Tom'},
{'id':'3456','name':'Art'}]
如何通过匹配name =’Tom’来有效地找到索引位置[0],[1]或[2]?
如果这是一维列表,则可以执行list.index(),但是我不确定如何通过搜索列表中的dict的值来进行操作。
I have a list of dicts:
list = [{'id':'1234','name':'Jason'},
{'id':'2345','name':'Tom'},
{'id':'3456','name':'Art'}]
How can I efficiently find the index position [0],[1], or [2] by matching on name = ‘Tom’?
If this were a one-dimensional list I could do list.index() but I’m not sure how to proceed by searching the values of the dicts within the list.
回答 0
tom_index = next((index for (index, d) in enumerate(lst) if d["name"] == "Tom"), None)
# 1
如果需要从名称重复获取,则应按名称对它们进行索引(使用字典),这样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'}
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
If you need to fetch repeatedly from name, you should index them by name (using a dictionary), this way get operations would be O(1) time. An idea:
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'}
回答 1
一个简单的可读版本是
def find(lst, key, value):
for i, dic in enumerate(lst):
if dic[key] == value:
return i
return -1
A simple readable version is
def find(lst, key, value):
for i, dic in enumerate(lst):
if dic[key] == value:
return i
return -1
回答 2
效率不高,因为您需要遍历列表检查其中的每个项目(O(n))。如果要提高效率,可以使用dict of dicts。关于这个问题,这是找到它的一种可能方法(不过,如果您要坚持使用这种数据结构,实际上使用 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
It won’t be efficient, as you need to walk the list checking every item in it (O(n)). If you want efficiency, you can use dict of dicts.
On the question, here’s one possible way to find it (though, if you want to stick to this data structure, it’s actually more efficient to use a generator as Brent Newey has written in the comments; see also tokland’s answer):
>>> L = [{'id':'1234','name':'Jason'},
... {'id':'2345','name':'Tom'},
... {'id':'3456','name':'Art'}]
>>> [i for i,_ in enumerate(L) if _['name'] == 'Tom'][0]
1
回答 3
这是一个查找字典索引位置(如果存在)的函数。
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
Here’s a function that finds the dictionary’s index position if it exists.
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
回答 4
似乎最合乎逻辑的是使用过滤器/索引组合:
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]
Seems most logical to use a filter/index combo:
names=[{}, {'name': 'Tom'},{'name': 'Tony'}]
names.index(filter(lambda n: n.get('name') == 'Tom', names)[0])
1
And if you think there could be multiple matches:
[names.index(n) for item in filter(lambda n: n.get('name') == 'Tom', names)]
[1]
回答 5
@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”的所有词典。
Answer offered by @faham is a nice one-liner, but it doesn’t return the index to the dictionary containing the value. Instead it returns the dictionary itself. Here is a simple way to get: A list of indexes one or more if there are more than one, or an empty list if there are none:
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()]
Output:
>>> [1]
What I like about this approach is that with a simple edit you can get a list of both the indexes and the dictionaries as tuples. This is the problem I needed to solve and found these answers. In the following, I added a duplicate value in a different dictionary to show how it works:
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()]
Output:
>>> [(1, {'id': '2345', 'name': 'Tom'}), (3, {'id': '4567', 'name': 'Tom'})]
This solution finds all dictionaries containing ‘Tom’ in any of their values.
回答 6
一行代码!!
elm = ([i for i in mylist if i['name'] == 'Tom'] or [None])[0]
One liner!?
elm = ([i for i in mylist if i['name'] == 'Tom'] or [None])[0]
回答 7
对于给定的可迭代项,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配方的第三方库。
For a given iterable, more_itertools.locate
yields positions of items that satisfy a predicate.
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
is a third-party library that implements itertools recipes among other useful tools.
回答 8
def search(itemID,list):
return[i for i in list if i.itemID==itemID]
def search(itemID,list):
return[i for i in list if i.itemID==itemID]