Given a list:
mylist = ['dog', 'cat', 'mouse_bear', 'lion_tiger_rabbit', 'ant']
I'd like a one-liner to return a new list:
['dog', 'cat', 'mouse', 'bear', 'lion', 'tiger', 'rabbit', 'ant']
Given a list:
mylist = ['dog', 'cat', 'mouse_bear', 'lion_tiger_rabbit', 'ant']
I'd like a one-liner to return a new list:
['dog', 'cat', 'mouse', 'bear', 'lion', 'tiger', 'rabbit', 'ant']
Another trick is first to join the list with underscores and then re-split it:
"_".join(mylist).split('_')
Just use 2 for
clauses in your comprehension, e.g.:
>>> mylist = ['dog', 'cat', 'mouse_bear', 'lion_tiger_rabbit', 'ant']
>>> [animal for word in mylist for animal in word.split('_')]
['dog', 'cat', 'mouse', 'bear', 'lion', 'tiger', 'rabbit', 'ant']
This is not a one liner, but is nevertheless a valid option to consider if you want to return a generator:
def yield_underscore_split(lst):
for x in lst:
yield from x.split('_')
>>> list(yield_underscore_split(mylist))
['dog', 'cat', 'mouse', 'bear', 'lion', 'tiger', 'rabbit', 'ant']
Original answer valid only for versions Python 3.3-3.7, kept here for interested readers. Do not use!
>>> list([(yield from x.split('_')) for x in l])
['dog', 'cat', 'mouse', 'bear', 'lion', 'tiger', 'rabbit', 'ant']
using the itertools
recipe to flatten a list you could do this:
from itertools import chain
mylist = ['dog', 'cat', 'mouse_bear', 'lion_tiger_rabbit', 'ant']
new_list = list(chain.from_iterable(item.split('_') for item in mylist))
print(new_list)
# ['dog', 'cat', 'mouse', 'bear', 'lion', 'tiger', 'rabbit', 'ant']
...or does the import statement violate your one-liner requirement?
Since so many answers here were posted (over ten), I thought it'd be beneficial to show some timing stats to compare the different methods posted:
-----------------------------------------
AChampion time: 2.6322
-----------------------------------------
hiro_protagonist time: 3.1724
-----------------------------------------
Eugene_Sh time: 1.0108
-----------------------------------------
cᴏʟᴅsᴘᴇᴇᴅ time: 3.5386
-----------------------------------------
jdehesa time: 2.9406
-----------------------------------------
mogga time: 3.1645
-----------------------------------------
Ajax1234 time: 2.4659
-----------------------------------------
Here's the script I used to test:
from timeit import timeit
setup = """
from itertools import chain
mylist = ['dog', 'cat', 'mouse_bear', 'lion_tiger_rabbit', 'ant']
"""
methods = {
'AChampion': """[animal for word in mylist for animal in word.split('_')]""",
'hiro_protagonist': """list(chain.from_iterable(item.split('_') for item in mylist))""",
'Eugene_Sh': """'_'.join(mylist).split('_')""",
'cᴏʟᴅsᴘᴇᴇᴅ': """list([(yield from x.split('_')) for x in mylist])""",
'jdehesa': """sum((s.split("_") for s in mylist), [])""",
'mogga': """[i for sublist in [j.split('_') for j in mylist] for i in sublist]""",
'Ajax1234': """list(chain(*[[i] if "_" not in i else i.split("_") for i in mylist]))"""
}
print('-----------------------------------------')
for author, method in methods.items():
print('{} time: {}'.format(author, round(timeit(setup=setup, stmt=method), 4)))
print('-----------------------------------------')
Each method is tested against the sample list given in the question about one million times. To keep things readable, each timing result was rounded to four decimal places.
Note: If you have a new, unique method that has not been posted here yet, contact me in the comments and I'll try to add a timing for it too.
Split each item into sublists and flatten them:
[item for sublist in mylist for item in sublist.split("_")]
One-liners are over-rated. Here's a solution using a "traditional" for
loop.
mylist = ['dog', 'cat', 'mouse_bear', 'lion_tiger_rabbit', 'ant']
out = []
for s in mylist:
if '_' in s:
out.extend(s.split('_'))
else:
out.append(s)
print(out)
output
['dog', 'cat', 'mouse', 'bear', 'lion', 'tiger', 'rabbit', 'ant']
This also works:
out = []
for s in mylist:
out.extend(s.split('_'))
It's shorter, but I think the previous version is clearer.
You can do:
mylist = ['dog', 'cat', 'mouse_bear', 'lion_tiger_rabbit', 'ant']
result = sum((s.split("_") for s in mylist), [])
print(result)
>>> ['dog', 'cat', 'mouse', 'bear', 'lion', 'tiger', 'rabbit', 'ant']
This works:
[i for sublist in [j.split('_') for j in mylist] for i in sublist]
mylist = ['dog', 'cat', 'mouse_bear', 'lion_tiger_rabbit', 'ant']
animals = [a for item in mylist for a in item.split('_')]
print (animals)
You can try this:
from itertools import chain
mylist = ['dog', 'cat', 'mouse_bear', 'lion_tiger_rabbit', 'ant']
new_list = list(chain(*[[i] if "_" not in i else i.split("_") for i in mylist]))
Output:
['dog', 'cat', 'mouse', 'bear', 'lion', 'tiger', 'rabbit', 'ant']
what I would actually do:
newlist = []
for i in mylist:
newlist += i.split('_')