Python: get a dict from a list based on something inside the dict
Solution 1
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.
Solution 2
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)
Solution 3
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.
Solution 4
Worked only with iter()
for me:
my_item = next(iter(item for item in my_list if item['id'] == my_unique_id), None)
Solution 5
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'}
Related videos on Youtube
johneth
Updated on January 09, 2020Comments
-
johneth over 4 years
I need to be able to find an item in a
list
(an item in this case being adict
) based on some value inside thatdict
. The structure of thelist
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
andvalue
can be any value (and the same),id
would be unique.I need to be able to get a
dict
from thislist
based on a uniqueid
. 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. -
agf almost 13 yearsThis keeps going through the list after it has found a match.
-
TyrantWave almost 13 yearsIf the ID should be unique, then doing a len() on this will show that you're getting non-unique IDs
-
agf almost 13 yearsIt's not a matter of the ids maybe being non-unique -- it's the difference between doing an average of
len(my_list)
comparisons orlen(my_list) // 2
comparisons. Your version does twice as much work (on average) as is necessary. -
agf almost 13 years
new_dict = dict((item['id'], item) for item in initial_list)
... why create an intermediate list thenzip
? -
TyrantWave almost 13 yearsFair enough - although knowing when you have two matching IDs can be useful sometimes, I suppose set size also comes into play.
-
agf almost 13 yearsTrue -- but he told us the
id
s were unique as part of the question. -
Augiwan almost 11 years@agf What do you recommend when there are multiple matches and you want to extract them in a list(of matched dicts)?
-
agf almost 11 years@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]
.