I have a list of strings like this:
['**', 'foo', '*', 'bar', 'bar', '**', '**', 'baz']
I want to replace the '**', '**'
with a single '**'
, but leave 'bar', 'bar'
intact. I.e. replace any consecutive number of '**'
with a single one. My current code looks like this:
p = ['**', 'foo', '*', 'bar', 'bar', '**', '**', 'baz']
np = [p[0]]
for pi in range(1,len(p)):
if p[pi] == '**' and np[-1] == '**':
continue
np.append(p[pi])
Is there any more pythonic way to do this?
Not sure about pythonic, but this should work and is more terse:
star_list = ['**', 'foo', '*', 'bar', 'bar', '**', '**', 'baz']
star_list = [i for i, next_i in zip(star_list, star_list[1:] + [None])
if (i, next_i) != ('**', '**')]
The above copies the list twice; if you want to avoid that, consider Tom Zych's method. Or, you could do as follows:
from itertools import islice, izip, chain
star_list = ['**', 'foo', '*', 'bar', 'bar', '**', '**', 'baz']
sl_shift = chain(islice(star_list, 1, None), [None])
star_list = [i for i, next_i in izip(star_list, sl_shift)
if (i, next_i) != ('**', '**')]
This can be generalized and made iterator-friendly -- not to mention more readable -- using a variation on the pairwise
recipe from the itertools
docs:
from itertools import islice, izip, chain, tee
def compress(seq, x):
seq, shift = tee(seq)
shift = chain(islice(shift, 1, None), (object(),))
return (i for i, j in izip(seq, shift) if (i, j) != (x, x))
Tested:
>>> list(compress(star_list, '**'))
['**', 'foo', '*', 'bar', 'bar', '**', 'baz']
This is in my opinion pythonic
result = [v for i, v in enumerate(L) if L[i:i+2] != ["**", "**"]]
the only "trickery" being used is that L[i:i+2]
is a list of one element when i == len(L)-1
.
Note that of course the very same expression can also be used as a generator
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