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?





are you expecting a single result? or a list of colors where the member_id is present?
– Vincent Pakson
Jul 3 at 4:09





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.

Popular posts from this blog

api-platform.com Unable to generate an IRI for the item of type

How to set up datasource with Spring for HikariCP?

Display dokan vendor name on Woocommerce single product pages