Python удаляет внутренние элементы последовательности в списке

1
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). Есть идеи?

  • 0
    Что произойдет, если у вас есть только 1 o Я предполагаю, что вы держите его?
  • 0
    Хорошо ... так что проблема состоит в том, чтобы уменьшить любую последовательность из 1 с до просто 'o', 'o' ? Есть ли какая-то причина, чтобы нуждаться в этом в понимании списка? Я ожидаю, что regex может сделать аккуратную работу на строке символов.
Показать ещё 2 комментария
Теги:

4 ответа

1
Лучший ответ

Следя за предыдущим и следующим элементом

Мы можем выполнить проверку предыдущего и следующего элемента и проверить, являются ли они также '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']
1

Если вы действительно хотите сделать это с одним списком понятий:

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]

должен работать для вашего примера.

1

Ты можешь сделать:

>>> 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']
0

Используя 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']

Ещё вопросы

Сообщество Overcoder
Наверх
Меню