Reputation: 11
I want the else statement in my list comprehension return nothing - i.e. I want the output of only the 2 if statements in my code. How can I do this please?
Data:
pleasant_sounding = ['Farm', 'Park', 'Hill', 'Green']
royal_sounding = ['Royal', 'Queen', 'King']
location_dict['Outer London'] = ['Brent Park', 'Woodford', 'Dollis Hill', 'Park Royal', 'Redbridge']
My code:
[ '{} sounds pleasant'.format(name)
if any(x in name for x in pleasant_sounding)
else '{} sounds grand'.format(name)
if any(y in name for y in royal_sounding)
else '' for name in location_dict['Outer London'] ]
My Output:
Brent Park sounds pleasant
''
Dollis Hill sounds pleasant
Park Royal sounds grand
''
Expected Output:
Brent Park sounds pleasant
Dollis Hill sounds pleasant
Park Royal sounds grand
Upvotes: 1
Views: 622
Reputation: 8180
Your list comprehension returns
['Brent Park sounds pleasant', '', 'Dollis Hill sounds pleasant', 'Park Royal sounds pleasant', '']
You just have to filter it:
>>> [t for t in <your list comprehension here> if t != '' ]
['Brent Park sounds pleasant', 'Dollis Hill sounds pleasant', 'Park Royal sounds pleasant']
That is:
>>> [t for t in ('{} sounds pleasant'.format(name)
... if any(x in name for x in pleasant_sounding)
... else '{} sounds grand'.format(name)
... if any(y in name for y in royal_sounding)
... else '' for name in location_dict['Outer London']) if t != '' ]
['Brent Park sounds pleasant', 'Dollis Hill sounds pleasant', 'Park Royal sounds pleasant']
I used a generator (note the parentheses) for the inner part since we don't need to construct the list but just to evaluate the values one by one. The code is still unclear, because you have, in the middle of the list comprehension, a complex expression that creates the string to return. You should use a function:
>>> def text(name):
... if any(x in name for x in pleasant_sounding):
... return '{} sounds pleasant'.format(name)
... elif any(y in name for y in royal_sounding):
... return '{} sounds grand'.format(name)
... return None # None is better than '' here
...
>>> [t for t in (text(name) for name in location_dict['Outer London']) if t is not None ]
['Brent Park sounds pleasant', 'Dollis Hill sounds pleasant', 'Park Royal sounds pleasant']
You can use a more functional style if you want:
>>> list(filter(None, map(text, location_dict['Outer London'])))
['Brent Park sounds pleasant', 'Dollis Hill sounds pleasant', 'Park Royal sounds pleasant']
I still see some redundancy in your if any(name ...)
tests. Imagine you have a lot of sounding types: your code will become tedious to maintain. You may use a more general method:
>>> soundings = [("pleasant", ['Farm', 'Park', 'Hill', 'Green']), ("grand", ['Royal', 'Queen', 'King'])}
>>> def text(name):
... for sounding_type, substrings in soundings:
... if any(x in name for x in substrings):
... return '{} sounds {}'.format(name, sounding_type)
... return None
...
>>> [t for t in (text(name) for name in location_dict['Outer London']) if t is not None]
['Brent Park sounds pleasant', 'Dollis Hill sounds pleasant', 'Park Royal sounds pleasant']
Note: this is Python 3.7, but you can adapt it to Python 2.7 (iteritems
instead of items
).
Upvotes: 1
Reputation: 114521
You can also add an if
in list comprehensions... your code could produce what you're looking for with some simplification and a little addition at the end:
['{} sounds pleasant'.format(name) if any(x in name for x in pleasant_sounding)
else '{} sounds grand'.format(name)
for name in location_dict['Outer London']
if any(x in name for x in pleasant_sounding+royal_sounding)]
In other words just a ternary expression, with a comprehension that includes a filtering condition
[<X> if <condition> else <Y>
for <var> in <container>
if <test>]
Upvotes: 1