foo = [0,0,0,0,1,1,1,1,1,1,0,0,0,1,1,1,0,0,1,1]
bar = [x if x==0 else 'o' for x in foo]
бар:
[0, 0, 0, 0,'o', 'o', 'o', 'o', 'o', 'o', 0, 0, 0, 'o', 'o', 'o', 0, 0, 'o', 'o']
Я бы хотел удалить внутренний "o" в этот момент, чтобы результат выглядел так:
[0, 0, 0, 0, 'o','o', 0, 0, 0, 'o','o', 0, 0, 'o', 'o']
Если возможно, я хотел бы сделать это в самом понимании списка, и я бы хотел избежать чего-либо с преобразованием в строку (поскольку моя фактическая задача для этого включает словари, а не 1 и 0). Есть идеи?
Мы можем выполнить проверку предыдущего и следующего элемента и проверить, являются ли они также 'o'
, если это так, мы не выдаем элемент, иначе мы это сделаем, например:
nbar1 = len(bar) - 1
[ x for i, x in enumerate(bar) if not (0 < i < nbar1 and bar[i] == bar[i-1] == bar[i+1] == 'o') ]
Вышеизложенное можно сделать более элегантным, используя chain
и zip
:
from itertools import chain, islice
prev = chain((None,), bar)
nxt = islice(chain(bar, (None, )), 1, None)
result = [ x for p, x, n in zip(prev, bar, nxt) if not (p == x == n == 'o') ]
где p
- "предыдущий элемент", x
- "текущий элемент", а n
- "следующий элемент".
Эти десять дают:
>>> [ x for p, x, n in zip(prev, bar, nxt) if not (p == x == n == 'o') ]
[0, 0, 'o', 'o', 0, 0, 'o', 'o', 0, 0, 'o']
Вышеупомянутое также будет работать с элементами, которые не равны 0
с, например:
>>> bar = [1, 3, 'o', 'o', 'o', 'o', 'o', 'o', 0, 0, 'o', 'o', 'o', 2, 0, 'o', 'o']
>>> prev = chain((None,), bar)
>>> nxt = islice(chain(bar, (None, )), 1, None)
>>> [ x for p, x, n in zip(prev, bar, nxt) if not (p == x == n == 'o') ]
[1, 3, 'o', 'o', 0, 0, 'o', 'o', 2, 0, 'o', 'o']
Мы также можем легко изменить его для работы с другим элементом (чем 'o'
), если это не то, что равно None
. Если это так, то мы можем, однако цепь других элементов к prev
и nxt
итерируемых.
Вышеупомянутое работает в линейном времени O (n) с n длиной обрабатываемого списка.
Альтернативой является использование itertools.groupby
для обнаружения "всплесков" символов, и в случае, если islice(..)
содержит 'o'
, мы islice(..)
до двух элементов:
из itertools import groupby, islice
[ x for k, g in groupby(bar) for x in (islice(g, 2) if k == 'o' else g) ]
снова уступая:
>>> [ x for k, g in groupby(bar) for x in (islice(g, 2) if k == 'o' else g) ]
[0, 0, 0, 0, 'o', 'o', 0, 0, 0, 'o', 'o', 0, 0, 'o', 'o']
Если вы действительно хотите сделать это с одним списком понятий:
bar=[x if x==0 else 'o' for i,x in enumerate(foo) if (i==0 or i==len(foo)-1) or x==0 or
foo[i-1]==0 or foo[i+1]==0]
должен работать для вашего примера.
Ты можешь сделать:
>>> foo = [0,0,0,0,1,1,1,1,1,1,0,0,0,1,1,1,0,0,1,1]
>>> from itertools import groupby
>>> [ext for c, grp in groupby(foo) for ext in (grp if c==0 else ['o']*min(2,len(list(grp))))]
[0, 0, 0, 0, 'o', 'o', 0, 0, 0, 'o', 'o', 0, 0, 'o', 'o']
Используя itertools.groupby
если k
равно 0
мы добавляем все элементы из этой группы, если k
является 'o'
мы добавляем только первый и последний, исключая средний 'o'
from itertools import groupby
bar = [0, 0, 'o', 'o', 'o', 'o', 'o', 'o', 0, 0, 'o', 'o', 'o', 0, 0, 'o', 'o']
new = []
for k, g in groupby(bar):
x = list(g)
if k == 0:
for i in x:
new.append(i)
elif k == 'o':
new.append(x[0])
new.append(x[-1])
print(new)
# [0, 0, 'o', 'o', 0, 0, 'o', 'o', 0, 0, 'o', 'o']
o
Я предполагаю, что вы держите его?1
с до просто'o', 'o'
? Есть ли какая-то причина, чтобы нуждаться в этом в понимании списка? Я ожидаю, чтоregex
может сделать аккуратную работу на строке символов.