Is there a more Pythonic way to iterate through dictionary keys looking for a value than this?
Is there a more Pythonic way to iterate through dictionary keys looking for a value than this?
Here is an example dictionary, colors
:
colors
{
"Red" : {
"members" : {
"153950039532134112" : {
"rank" : 1,
"score" : 43,
"time" : 1530513303
}
},
"rank" : 2,
"score" : 43
},
"Blue" : {
"members" : {
"273493248051539968" : {
"rank" : 1,
"score" : 849,
"time" : 1530514923
},
"277645262486011904" : {
"rank" : 2,
"score" : 312,
"time" : 1530513964
},
"281784064714487810" : {
"rank" : 3,
"score" : 235,
"time" : 1530514147
}
},
"rank" : 1,
"score" : 1396
}
}
For the sake of this example, let's assume that there are many more color-named keys in this dictionary. Now, assume I am looking for a particular member ID.
for key, value in colors.items():
if member_id in value['members']:
return True
Is there a simpler, possibly one-line way to do this?
Then you don't need
colors[key]
because this is just value
so it is equivalent to if member_id in value['members']
. But this is a minor thing as indexing into a dict
is an O(1)
operation.– AChampion
Jul 3 at 4:11
colors[key]
value
if member_id in value['members']
dict
O(1)
4 Answers
4
Here is another one-liner that uses any
:
any
return any(member_id in color['members'] for color in colors.values())
Here's a one-line way of doing this:
member_id="273493248051539968"
[k for k, v in colors.items() if member_id in v['members']]
Output:
['Blue']
This seems unnecessarily complicated as you know it is in the
['members']
of the v
, so [k for k, v in colors.items() if member_id in v['members']]
would do the same, assuming the OP is not simply looking for a True
/ False
return.– AChampion
Jul 3 at 4:18
['members']
v
[k for k, v in colors.items() if member_id in v['members']]
True
False
This will output a list of all of the keys containing that member_id. It's good if that's what you want, but that also means it has to search the whole dict and won't shortcut, unlike the long solution in the question, which is bad since
colors
is supposed to be a big dict, and the extra work is useless if member IDs only appear once each.– gilch
Jul 3 at 5:14
colors
next((k for k, v in colors.items() if member_id in v['members']), None)
Evaluates to the first color key with that member_id
, like 'Blue'
(or None
if not found).
member_id
'Blue'
None
Generator expressions are lazy, so it will stop searching as soon as it finds a match.
This is a weird formulation that is not very pythonic at all. It is also no more efficient than
any
with a generator, which is an existing answer.– Matthew Story
Jul 3 at 4:41
any
@MatthewStory No it won't, try them. The
next
function takes an additional default argument, which suppresses the StopIteration
behavior. And unlike any
this can find the first key.– gilch
Jul 3 at 4:43
next
StopIteration
any
Oh neat, I didn't know that about next's extra arg. Still very weird and no more efficient than
any
with a generator.– Matthew Story
Jul 3 at 4:44
any
You could use a list comprehension which is just a concise way to do your for loop and conditional statement.
The list comprehension below will return a color value when the member_id
is present. If you check that the returned list has at least one value, you know the member_id
was present in at least one color dict. If you make two lines and assign the output you could also have the color dict handy, in case you need to modify or read any of its state.
member_id
member_id
any([color for color in colorDict if member_id in colorDict[color]['members']])
any([color for color in colorDict if member_id in colorDict[color]['members']])
I would say this is more pythonic than the example in your question, but sometimes list comprehensions can be unclear when there is more complexity involved. For example, if you needed two loops and two conditions then a list comprehension may not be the best choice. Overall they're an extremely useful tool, but it's up to you to decide when to use them.
I don't think this would work. Maybe you meant
... in colorDict[color]['members']
? Also your square brackets are not balanced.– Selcuk
Jul 3 at 4:54
... in colorDict[color]['members']
Thanks. You are correct. I've editted my answer.
– Michael R
Jul 3 at 18:19
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
are you expecting a single result? or a list of colors where the member_id is present?
– Vincent Pakson
Jul 3 at 4:09