压缩 python 列表中所有连续的

squash all consecutive ones in a python list

我有包含 0s1s 的变量列表,例如:

l1 = [1,1,1,0,1,1]
l2 = [0,1,1,0,1,1,0,0,1]

创建压缩所有连续 1s.

的新列表的最有效方法是什么

所以结果是:

l1_new = [1,0,1]
l2_new = [0,1,0,1,0,0,1]

Hint: numpy/vectorization or some logical operation would be great!

这是一个可能的解决方案

arr = [0,1,1,0,1,1,0,0,1]

previous_value = None
new_lst = []

for elem in arr:
   if elem != previous_value:
       new_lst.append(elem)
       previous_value = elem

print(new_lst)

其中 arr 是您想要的任何列表,它适用于包括字符串在内的任何内容。

要利用 NumPy,我们需要数组,因此在转换后,我们将创建适当的掩码和索引 -

def squash1s(a):
    a = np.asarray(a)
    m = a==1
    return a[np.r_[True,m[:-1]!=m[1:]] | (a==0)]

样本运行 -

In [64]: l1 = [1,1,1,0,1,1]
    ...: l2 = [0,1,1,0,1,1,0,0,1]

In [65]: squash1s(l1)
Out[65]: array([1, 0, 1])

In [66]: squash1s(l2)
Out[66]: array([0, 1, 0, 1, 0, 0, 1])

基准测试

由于我们关心的是性能效率,所以让我们对 NumPy 进行基准测试,因为它们应该非常高效。

其他建议的解决方案

# @yatu's solution
def yatu_diff(l):
    a = np.asarray(l)
    return a[~((np.diff(a,prepend=False)==0) & a==1)]

# PaulPanzer's suggestion/soln
def pp_concat(a):
    a = np.asarray(a)
    return a.repeat(1-(a*np.concatenate([[0],a[:-1]])))

使用 benchit 包(几个基准测试工具打包在一起;免责声明:我是它的作者)对提议的解决方案进行基准测试。

import benchit

funcs = [squash1s, yatu_diff, pp_concat]

# With ~30% 0s
in_ = [(np.random.rand(n)>0.3).astype(int) for n in 10**np.arange(4)]
t = benchit.timings(funcs, in_)
t.plot(logx=True, save='timings30.png')

# With ~70% 0s
in_ = [(np.random.rand(n)>0.7).astype(int) for n in 10**np.arange(4)]
t = benchit.timings(funcs, in_)
t.plot(logx=True, save='timings70.png')

~30% 0s :

~70% 0s :

使用 while 循环,

l1 = [1,1,1,0,1,1]
i = 0

while i < len(l1)-1:
    if l1[i] == l1[i+1]:
        del l1[i]
    else:
        i = i+1
print(l1)

我在 geeksforgeeks 上找到的另一个是,

from itertools import zip_longest 


test_list = [1, 4, 4, 4, 5, 6, 7, 4, 3, 3, 9] 

res = [i for i, j in zip_longest(test_list, test_list[1:]) 
                                                if i != j] 

这是使用 np.diffbitwise operations 的一种方法:

l1 = [1,1,1,0,1,1]
l2 = [0,1,1,0,1,1,0,0,1]

a = np.array(l2)
a[~((np.diff(a,prepend=False)==0) & (a==1))]
# array([0, 1, 0, 1, 0, 0, 1])

或者第一个例子:

a = np.array(l1)
a[~((np.diff(a,prepend=False)==0) & (a==1))]
#array([1, 0, 1])

给定

lst_1 = [1, 1, 1, 0, 1, 1]
lst_2 = [0, 1, 1, 0, 1, 1, 0, 0, 1]
lst_3 = [0, 1, 1, 0, 1, 1, 0, 0, 1, 1]

代码

def compress_values(seq, value=1):
    """Yield a value in isolation."""

    for here, nxt in zip(seq, seq[1:]):

        if here == nxt == value:
            continue
        else:
            yield here

    yield nxt        

演示

assert [1, 0, 1] == list(compress_values(lst_1))
assert [0, 1, 0, 1, 0, 0, 1] == list(compress_values(lst_2))
assert [0, 1, 0, 1, 0, 0, 1] == list(compress_values(lst_3))

详情

滑动一个二元组window。如果值彼此相等且目标 value,则跳过。否则产生值。

另一种更通用的方法:


import itertools as it


def squash(seq, values=(1,)):
    """Yield singular values in isolation."""

    for k, g in it.groupby(seq):

        if k in values:
            yield k
        else:
            yield from g