Python: get a dict from a list based on something inside the dict
Asked Answered
I

8

100

I need to be able to find an item in a list (an item in this case being a dict) based on some value inside that dict. The structure of the list I need to process looks like this:

[
    {
        'title': 'some value',
        'value': 123.4,
        'id': 'an id'
    },
    {
        'title': 'another title',
        'value': 567.8,
        'id': 'another id'
    },
    {
        'title': 'last title',
        'value': 901.2,
        'id': 'yet another id'
    }
]

Caveats: title and value can be any value (and the same), id would be unique.

I need to be able to get a dict from this list based on a unique id. I know this can be done through the use of loops, but this seems cumbersome, and I have a feeling that there's an obvious method of doing this that I'm not seeing thanks to brain melt.

Institution answered 16/8, 2011 at 13:53 Comment(0)
M
162
my_item = next((item for item in my_list if item['id'] == my_unique_id), None)

This iterates through the list until it finds the first item matching my_unique_id, then stops. It doesn't store any intermediate lists in memory (by using a generator expression) or require an explicit loop. It sets my_item to None of no object is found. It's approximately the same as

for item in my_list:
    if item['id'] == my_unique_id:
        my_item = item
        break
else:
    my_item = None

else clauses on for loops are used when the loop is not ended by a break statement.

Molly answered 16/8, 2011 at 13:57 Comment(4)
@Molly What do you recommend when there are multiple matches and you want to extract them in a list(of matched dicts)?Lexie
@UGS If you need to scan the whole list and build up a result list, and not just find the first match, you can't do better than a list comprehension like [item for item in my_list if item['id'] == my_unique_id].Molly
This will not work for nested dictMidis
@Midis can you give an example?Molly
A
31

If you have to do this multiple times, you should recreate a dictionnary indexed by id with your list :

keys = [item['id'] for item in initial_list]
new_dict = dict(zip(keys, initial_list)) 

>>>{
    'yet another id': {'id': 'yet another id', 'value': 901.20000000000005, 'title': 'last title'}, 
    'an id': {'id': 'an id', 'value': 123.40000000000001, 'title': 'some value'}, 
    'another id': {'id': 'another id', 'value': 567.79999999999995, 'title': 'another title'}
}

or in a one-liner way as suggested by agf :

new_dict = dict((item['id'], item) for item in initial_list)
Agrobiology answered 16/8, 2011 at 13:58 Comment(1)
new_dict = dict((item['id'], item) for item in initial_list)... why create an intermediate list then zip?Molly
A
8

I used this, since my colleagues are probably more able to understand what's going on when I do this compared to some other solutions provided here:

[item for item in item_list if item['id'] == my_unique_id][0]

And since it's used in a test, I think the extra memory usage isn't too big of a deal (but please correct me if I am wrong). There's only 8 items in the list in my case.

Assiniboine answered 8/1, 2020 at 14:45 Comment(0)
A
4

Worked only with iter() for me:

my_item = next(iter(item for item in my_list if item['id'] == my_unique_id), None)
Agribusiness answered 11/4, 2019 at 7:25 Comment(0)
T
2

You can create a simple function for this purpose:

lVals = [{'title': 'some value', 'value': 123.4,'id': 'an id'},
 {'title': 'another title', 'value': 567.8,'id': 'another id'},
 {'title': 'last title', 'value': 901.2, 'id': 'yet another id'}]

def get_by_id(vals, expId): return next(x for x in vals if x['id'] == expId)

get_by_id(lVals, 'an id')
>>> {'value': 123.4, 'title': 'some value', 'id': 'an id'}
Twitter answered 16/8, 2011 at 14:7 Comment(0)
I
1

Just in case, if you want lookup search on the basis of the key of a dictionary.

my_item = next((item for item in my_list if item.has_key(my_unique_key)), None)

For 3.0+, has_key() has been deprecated. Instead use in:

my_item = next((item for item in mylist if 'my_unique_key' in item), None)

https://docs.python.org/3.0/whatsnew/3.0.html#builtins

Incognizant answered 6/6, 2019 at 8:50 Comment(0)
P
0
In [2]: test_list
Out[2]: 
[{'id': 'an id', 'title': 'some value', 'value': 123.40000000000001},
 {'id': 'another id', 'title': 'another title', 'value': 567.79999999999995},
 {'id': 'yet another id', 'title': 'last title', 'value': 901.20000000000005}]

In [3]: [d for d in test_list if d["id"] == "an id"]
Out[3]: [{'id': 'an id', 'title': 'some value', 'value': 123.40000000000001}]

Use list comprehension

Progression answered 16/8, 2011 at 13:58 Comment(5)
This keeps going through the list after it has found a match.Molly
If the ID should be unique, then doing a len() on this will show that you're getting non-unique IDsProgression
It's not a matter of the ids maybe being non-unique -- it's the difference between doing an average of len(my_list) comparisons or len(my_list) // 2 comparisons. Your version does twice as much work (on average) as is necessary.Molly
Fair enough - although knowing when you have two matching IDs can be useful sometimes, I suppose set size also comes into play.Progression
True -- but he told us the ids were unique as part of the question.Molly
F
0

You can achieve this using a simple loop or . If you want to find an item based on a specific value , you can iterate over the list and check each dictionary's value . Here's how you can do it :

# Function to find item based on value
def find_item_by_value(data_list, value_to_find):
for item in data_list:
    if item['value'] == value_to_find:
        return item
return None

# Example usage
value_to_find = 567.8
found_item = find_item_by_value(data, value_to_find)
if found_item:
    print("Item found:", found_item)
else:
    print("Item not found")

This function find_item_by_value will return the first item it finds with the specified value. If no item is found , it returns None .

Frere answered 13/3 at 11:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.