Python: Check if any list element is a key in a dictionary
Given the following code
all_options = { "1": "/test/1", "2": "/test/2", "3": "/test/3" }
s开发者_Go百科elected_options = [ "1", "3" ]
How do I get the entries from all_options where the key matches an entry in selected_options?
I started down the path of using a List Comprehension, but I'm stuck on the last clause:
final = ()
[ final.append(option) for option in all_options if ... ]
Thank you
Just like this?
>>> dict((option, all_options[option]) for option in selected_options if option in all_options)
{'1': '/test/1', '3': '/test/3'}
From Python 2.7 and 3 onwards, you can use the dict comprehension syntax:
{option : all_options[option] for option in selected_options if option in all_options}
Or if you just want the values:
>>> [all_options[option] for option in selected_options if option in all_options]
['/test/1', '/test/3']
[option for option in all_options if option in selected_options]
You may want to make a set
of selected_options
and use that instead if there are many.
How do I get the entries from all_options where the key matches an entry in selected_options?
With a comprehension. We have two kinds: list comprehensions and generator comprehensions.
Note that this depends on what you mean by "entries". If you want a dict
with the key/value pairs that match, then you'll need a comprehension that creates the key/value pairs, and then use that to create a dict by feeding it to the dict
constructor.
There is a special syntax rule that says that if we call something callable (like, say, a class constructor) with just one argument, and that argument is a generator comprehension, then we only need one pair of parentheses (instead of two: one to call the function and another to mark the comprehension as a comprehension). This lets us write very natural-looking things.
On the other hand, if you just want a list
of keys, then you can just use a list comprehension. (You could pass a generator comprehension to the list
constructor, too.)
I started down the path of using a List Comprehension...
You have the wrong idea, fundamentally, about how they work. You don't use them to perform an action repeatedly; you use them to calculate a result repeatedly. You wouldn't make an append
call in the first part of the statement because (a) the comprehension is already building the sequence for you, so there's no reason to create another empty sequence to append to; (b) the append
call returns None
after doing the appending, so you end up with a list of None values that you subsequently throw away.
A list comprehension creates a value. A generator comprehension also creates a value, but it's a generator (so you have to extract its values to use them).
So, how do we write the code?
A list
of keys looks like this: for each key in the dict
(iterating over a dict
iterates over its keys), we want that key (with no modification), only if the key is in our other list
. That is, we want [key for key in all_options if key in selected_options]
. And that's exactly how you write it in Python. A language could hardly read any more naturally while still being unambiguous.
A dict
of key-value pairs looks like this: for each key-value pair in the key-value pairs of the dict
, we want that pair, only if the key is in our other list
. We want to make a dict
using those key-value pairs, so we wrap the comprehension in the dict
constructor. To get key-value pairs from a dict, we iterate over its .items()
. So, we want a dict
constructed from a key and value, for each key and value in the items of the original dict
, where the key is in the other list
. And again, that's exactly what we write: dict((key, value) for (key, value) in all_options if key in selected_options)
.
In more recent versions of Python, we can also use a "dict comprehension", which is basically syntactic sugar so that we can write something that looks more like the list comprehension.
Use set()
instead, and take advantage of the intersection operation:
>>> final = set(all_options.keys()) & set(selected_options)
>>> print(final)
{'1', '3'}
The above only returns the keys, but NullUserException notes that the question may want the value as well, using a dict comprehention:
>>> {x: all_options[x] for x in set(all_options.keys()) & set(selected_options)}
{'1': '/test/1', '3': '/test/3'}
For completeness, here's just the value:
>>> [all_options[x] for x in set(all_options.keys()) & set(select_options)]
['/test/1', '/test/3']
The below is wrong. Using set()
iterates over both lists, instead of just one.
Using sets is better assuming the options become large. The conditional list comprehensions check every item in one of the containers, but a set intersection takes advantage of Python's excellent hashing. Even the list comprehension here only looks up the desired keys in
all_options
.
I'm not sure which exact contents you're trying to return, so I'm giving a couple of choices:
if your trying to return: ['1', '3']
[option for option in all_options if option in selected_options]
OR
if you're trying to return: ['/test/1', '/test/3']
[all_options[option] for option in all_options if option in selected_options]
精彩评论