Python移除列表中序列的内部项

时间:2018-10-10 21:16:49

标签: python

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)。有什么想法吗?

4 个答案:

答案 0 :(得分: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') ]

可以使用chainzip使以上内容更加优美:

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更好)一起使用。如果是这种情况,我们可以将其他元素链接到prevnxt可迭代对象。

以上内容在线性时间 O(n)中起作用,其中 n 是要处理的列表的长度。

通过分组和切片

一种替代方法是使用itertools.groupby来检测字符的“突发”,并且如果突发中包含'o'个字符,则我们islice(..)最多包含两个元素:

从itertools导入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 :(得分: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]

应该适合您的示例。

答案 2 :(得分: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']

答案 3 :(得分:0)

如果itertools.groupbyk,则使用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']