[英]Python remove inner items of a sequence in a list
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]
bar: 酒吧:
[0, 0, 0, 0,'o', 'o', 'o', 'o', 'o', 'o', 0, 0, 0, 'o', 'o', 'o', 0, 0, 'o', 'o']
I would like to remove the inner 'o' at this point so that the result looks like so: 我想在此处删除内部'o',以便结果如下所示:
[0, 0, 0, 0, 'o','o', 0, 0, 0, 'o','o', 0, 0, 'o', 'o']
If possible, I'd like to do this within the list comprehension itself, and I would like to avoid anything with converting to a string (as my actual task for this involves dictionaries rather than 1's and 0's). 如果可能的话,我想在列表理解本身中这样做,并且我想避免转换为字符串的任何事情(因为我的实际任务涉及字典而不是1和0)。 Any ideas?
有任何想法吗?
We can perform a check on the previous and next element, and check if these are 'o'
s as well, if so, we do not yield the element, otherwise we do, like: 我们可以检查上一个和下一个元素,并检查它们是否也是
'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') ]
The above can be made more elegant by using chain
and zip
: 使用
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') ]
where p
is the "previous item", x
is the "current item", and n
is the "next item". 其中
p
是“前一项”, x
是“当前项”, n
是“下一项”。
This ten yields: 这十个产量:
>>> [ 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']
The above will also work with elements that are not 0
s, for example: 以上内容也适用于非
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']
We can also easily change it to work with another element (than 'o'
), as long as it is not something that is equal to None
. 我们也可以轻松地将其更改为与另一个元素(而不是
'o'
)一起使用,只要它不是等于None
东西。 If that is the case, we can however chain other elements to the prev
and nxt
iterables. 如果是这种情况,我们可以将其他元素链接到
prev
和nxt
iterables。
The above works in linear time O(n) with n the length of the list to process. 以上工作在线性时间O(n)中,其中n为要处理的列表的长度。
An alternative is to use itertools.groupby
to detect "bursts" of characters, and in case the burst contains 'o'
s, we islice(..)
up to two elements: 一个替代方案是使用
itertools.groupby
以检测字符的“脉冲串”,并在情况下,突发包含'o'
S,我们islice(..)
最多两个元素:
from itertools import groupby, islice 来自itertools import groupby,islice
[ x for k, g in groupby(bar) for x in (islice(g, 2) if k == 'o' else g) ]
again yielding: 再次屈服:
>>> [ 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']
If you really want to do it with one comprehension list: 如果你真的想用一个理解列表来做:
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]
should work for your example. 应该适合你的榜样。
You can do: 你可以做:
>>> 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']
Using itertools.groupby
if k
is 0
we append all the items from that group, if k
is 'o'
we only append the first and last excluding the middle 'o'
's 使用
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']
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.