开发者

Find the index of a dict within a list, by matching the dict's value

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-dime开发者_JAVA百科nsional list I could do list.index() but I'm not sure how to proceed by searching the values of the dicts within the list.


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))

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


A simple readable version is

def find(lst, key, value):
    for i, dic in enumerate(lst):
        if dic[key] == value:
            return i
    return -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


Seems most logical to use a filter/index combo:

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

And if you think there could be multiple matches:

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


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.


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


One liner!?

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


I needed a more general solution to account for the possibility of multiple dictionaries in the list having the key value, and a straightforward implementation using list comprehension:

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


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


The following will return the index for the first matching item:

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


my answer is better in one a dictionary to use

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

I request keys from the dictionary, then I translate the list if it is not added, there will be an error then I use it as a list. but on your code:

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


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜