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

Question:

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.

Asked By: ensnare

||

Answers:

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'}
Answered By: tokland

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
Answered By: aeter

A simple readable version is

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

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
Answered By: martineau

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]
Answered By: michael salmon

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.

Answered By: pylang

One liner!?

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

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.

Answered By: stanely
def search(itemID,list):
     return[i for i in list if i.itemID==itemID]
Answered By: Rohan Kumara

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] 
Answered By: Sebastian Timar

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

['Tom' in i['name'] for i in list].index(True)
Answered By: Dan Boschen

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
Answered By: AIRC.Group
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.