1

Just want to ask if this particular set of code can be expressed into a one-liner list comprehension:

files = ["country_Maldives", "country_East Timor", "country_Laos", "country_Uruguay"]
accountlist = ["Laos", "Maldives"]

final_list = []
for account in accountlist:
    included = [file for file in files if account in file][0]
    final_list.append(included)

Thank you.

ambmil
  • 115
  • 3
  • 9

3 Answers3

2

Since your code just fetches all the matches and picks the first one with:

[file for file in files if account in file][0]

You could instead use next() to keep retrieving the next item until a match is found:

result = [next(file for file in files if account in file) for account in accountlist]

print(result)
# ['country_Laos', 'country_Maldives'] => Same output as your original code

The only problem with the above is that a StopIteration exception will be raised if the iterator is exhausted and no match has been found. To prevent this, we can supply a default value instead, such as None, so it returns this value instead of the exception.

[next((file for file in files if account in file), None) for account in accountlist]

Then if we wanted to filter out None matches, we could use another list comprehension to do that:

filtered = [file for file in result if file is not None]
RoadRunner
  • 25,803
  • 6
  • 42
  • 75
1

Check out any/all operators:

ret = [file for file in files if any(account in file for account in accountlist)]

https://docs.python.org/3/library/functions.html#any

UDP

Oneliner above returns list of ALL files each of which contains ANY of accounts. If you want to find only first entries by given condition, operator next is also worth mentioning:

ret = [next((file for file in files if account in file), []) for account in accountlist]

https://docs.python.org/3/library/functions.html#next

Michail Highkhan
  • 517
  • 6
  • 18
0

just another way, nesting the for loops...

In [19]: files = ["country_Maldives", "country_East Timor", "country_Laos", "country_Uruguay"]
    ...: accountlist = ["Laos", "Maldives"]

In [20]: res=[file  for acc in accountlist for file in files  if acc in file.split('_')]

In [21]: res
Out[21]: ['country_Laos', 'country_Maldives']
teddcp
  • 1,514
  • 2
  • 11
  • 25
  • This is absolutely incorrect. What if `files = ["country_Maldives", "country_East Timor", "country_Laos", "country_2_Laos", "country_Uruguay"]`? – Booboo May 15 '20 at 13:16
  • @Booboo,I have updated the answer now. Thanks for the correction. – teddcp May 15 '20 at 13:19
  • I still get `['country_Laos', 'country_2_Laos', 'country_Maldives']` with my input. – Booboo May 15 '20 at 13:21
  • @Booboo, yes that's what is expected . As Laos is present, so it should be returned. right ? – teddcp May 15 '20 at 13:23
  • **Run my input against the OP's code using my value for the variable `files`**. Notice that the OP is selecting element 0 of all the matches, i.e. the first match only in the country list for each item in the account list. Look at @RoadRunner's answer, especially his description about using `next` to get the first match. – Booboo May 15 '20 at 13:25