In Python I'm attempting to use a list comprehension to create a list where any string in one list starts with any string in another.
For example, say I have a list of three names Alan
, Bob
and Carl
. I wish to return a list of names that start with any string from another list, this time containing Bo
, Da
and Fr
. There for I'd expect only ['Bob']
to be returned.
However, using the following example I'm seeing all of the names returned.
>>> starts_with=('Bo', 'Da', 'Fr')
>>> names = ['Alan', 'Bob', 'Carl']
>>> [n for n in names if [n.startswith(s) for s in starts_with]]
['Alan', 'Bob', 'Carl']
My issue seems to be that the inner list comprehension is returning a list of boolean values, so the list that is being checked by the if
in the main list comprehension is never empty.
>>> starts_with=('Bo', 'Da', 'Fr')
>>> ['Alan'.startswith(s) for s in starts_with]
[False, False, False]
>>> ['Bob'.startswith(s) for s in starts_with]
[True, False, False]
>>> ['Carl'.startswith(s) for s in starts_with]
[False, False, False]
How can I amend my code so that only ['Bob']
is returned?
CodePudding user response:
Use any()
, which is a builtin function that returns True
if any
element of an input iterable is true:
>>> starts_with=('Bo', 'Da', 'Fr')
>>> names = ['Alan', 'Bob', 'Carl']
>>> [n for n in names if any(n.startswith(s) for s in starts_with)]
['Bob']
CodePudding user response:
Simple and compact solution
[n for n in names for sw in starts_with if n.startswith(sw)]
As David asked why not use any
instead :
Unraveling Samwise answer
[n for n in names if any(n.startswith(s) for s in starts_with)]
would be
for n in names:
for s in starts_with:
[add s to temp list say temp]
for t in temp:
if(t): # if t is true
[add n to result list]
CodePudding user response:
You can avoid using any()
with a simple double for
loop comprehension:
starts_with=['Bo', 'Da', 'Fr']
names = ['Alan', 'Bob', 'Carl']
out = [i for i in names for j in starts_with if i.startswith(j)]
print(out)
['Bob']