I'm trying to merge list items with previous items if they don't contain a certain prefix, and adding a \n
between said list items when doing so.
prefix = '!'
cmds = ['!test','hello','world','!echo','!embed','oh god']
output = ['!test\nhello\nworld','!echo','!embed\noh god']
I tried something like
for i in list(range(0,len(cmds))):
if not cmds[i+1].startswith(prefix):
cmds[i] += cmds.pop(i+1)
but always get the list index out of range
error.
My apologies if this is badly worded, or seems like an obvious fix, I'm fairly new to python/programming.
Edit:
I had managed to get it to work with
prefix = '!'
cmds = ['!test','hello','world','!echo','!embed','oh god']
print(list(range(0,len(cmds))))
for i in reversed(range(len(cmds))):
if not cmds[i].startswith(prefix):
cmds[i-1] += '\n'+cmds.pop(i)
print(cmds)
but your answers seem so much neater and efficient. Much thanks everyone
You can concatenate multiple lists into one list by using the * operator. For Example, [*list1, *list2] – concatenates the items in list1 and list2 and creates a new resultant list object. Usecase: You can use this method when you want to concatenate multiple lists into a single list in one shot.
In python, we can use the + operator to merge the contents of two lists into a new list. For example, We can use + operator to merge two lists i.e. It returned a new concatenated lists, which contains the contents of both list_1 and list_2.
I propose to create a new list, as you showed in your problem specification:
prefix = '!'
cmds = ['!test','hello','world','!echo','!embed','oh god']
output = []
for cmd in cmds:
if cmd.startswith(prefix) or not output:
output.append(cmd)
else:
output[-1] += "\n" + cmd # change the string in the last element of output
The result is:
>>> output
['!test\nhello\nworld', '!echo', '!embed\noh god']
Here's a one liner solution using itertools.groupby
and itertools.accumulate
:
from itertools import accumulate, groupby
from operator import itemgetter
x = ['!test','hello','world','!echo','!embed','oh god']
cumsum = accumulate(map(lambda s: s.startswith('!'), x))
result = ['\n'.join(map(itemgetter(0), g)) for _, g in groupby(zip(x, cumsum), itemgetter(1))]
This looks like a two liner because I wanted to make it semi-legible, but that's not always necessary:
result = ['\n'.join(map(itemgetter(0), g)) for _, g in groupby(zip(x, accumulate(map(lambda s: s.startswith('!'), x))), itemgetter(1))]
cumsum
provides the number of elements starting with !
found so far. This makes for a nice key to groupby
. It works by accumulating the booleans returned by str.startswith
into an integer.
The final result uses cumsum
as the key, but joins the grouped elements of x
with newlines.
Here's an IDEOne Link to play with.
You can do it with list comprehension "also".
In [1]: cmds = ['!test','hello','world','!echo','!embed','oh god']
In [2]: prefix = '!'
In [3]: inds = [i for i, x in enumerate(cmds) if prefix in x]
In [4]: inds.append(len(cmds))
In [5]: lens = list(zip(inds, inds[1:]))
# [(0, 3), (3, 4), (4, 6)]
In [6]: ["\n".join(cmds[a:b]) for a, b in lens]
Out[6]: ['!test\nhello\nworld', '!echo', '!embed\noh god']
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With