Python Find matching item in a list of dictionaries

Question:

I have a big list of dictionaries. Each dictionary contains timeseries data of each sensor when each data point is collected. I want to know the index location of a specific sensor and date. So, I can update the sensor value.
My code:

big_list = [
dict({'sensor':12,'time':'2022-02-03','value':10}),
dict({'sensor':22,'time':'2022-02-03','value':12}),
dict({'sensor':32,'time':'2022-02-03','value':24}),
dict({'sensor':12,'time':'2022-02-04','value':17}),
dict({'sensor':22,'time':'2022-02-04','value':13}),
dict({'sensor':32,'time':'2022-02-04','value':21})]

# Find index of an item 
item_to_find = dict({'time':'2022-02-03','sensor':32})
# solution
big_list.index(item_to_find)

Present output:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: {'sensor': 32, 'time': '2022-02-03'} is not in list

Expected output:

2
Asked By: Mainland

||

Answers:

I know this may not be the most efficient solution, but it was the best I could do. 🙂

sensor = 32
time = '2022-02-03'

for item in big_list:
    if item.get('sensor') == sensor and item.get('time') == time:
        print(big_list.index(item))
Answered By: cyberghost

You can try next() + enumerate():

idx = next(
    i for i, d in enumerate(big_list) if all(d[k] == v for k, v in item_to_find.items())
)
print(idx)

Prints:

2

OR: You can add default parameter to next() in case the item is not found:

# returns None if the item is not found
idx = next(
    (i for i, d in enumerate(big_list) if all(d[k] == v for k, v in item_to_find.items())), None
)
print(idx)
Answered By: Andrej Kesely

Try this:

list(
    map(
        lambda x: {'time': x['time'], 'sensor': x['sensor']} == item_to_find,
        big_list
    )
).index(True)

Explanation:

  • use map() to extract the values to be compared, stripping away the value
  • in the function being mapped, make the comparison with item_to_find – this will return an iterator which will yield True for a match or False for a non-match.
  • turn the resulting iterator into a list with list()
  • find the first occurrence in this list of True and return the index.

You might also want to look at pandas that makes all this a lot more easy to handle.

Answered By: Brad

Same idea as @Andrej but you can use lambda function for clearer intention

same_time_and_sensor = lambda item: item['sensor'] == item_to_find['sensor'] and item['time'] == item_to_find['time']

index = next((i for i, item in enumerate(big_list) if same_time_and_sensor(item)), None)

print(index)

Here next() will return index of the first match or None if no match found.

Answered By: Quan VO

If you are looking for a specific date and sensor you can make a loop to iterate over every dictionary in the list and save the index of matching item in the list of index:

sensor = 32
date = '2022-02-03'

ind = []
for idx, dt in enumerate(big_list):
    if dt['sensor'] == sensor and dt['time'] == date:
        ind.append(idx)

print(ind)
Answered By: SALAR

In the meantime, I found a online answer as well:

solution_item = next(filter(lambda s: s['time']==item_to_find['time'] and s['sensor']==item_to_find['sensor'],big_list))

{'sensor': 32, 'time': '2022-02-03', 'value': 24}

For index of the solution

big_list.index(solution_item)

2
Answered By: Mainland

I would recommend converting your list of dictionaries to a dataframe. Especially if you need to do this multiple times.

import pandas as pd

big_df = pd.DataFrame(big_list).reset_index()
i = big_df[(big_df['sensor']==32)&(big_df['time']=='2022-02-03')]['index'].item()
print(i)
Answered By: jpeper