squash all consecutive ones in a python list

自古美人都是妖i 提交于 2021-02-05 07:24:06

问题


I have variable lists filled with 0s and 1s, like:

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

what is the most efficient way to create new lists that squash all consecutive 1s.

So the result would be:

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

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


回答1:


Here's one approach using with np.diff and bitwise 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])

Or for the first example:

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



回答2:


To leverage NumPy, we would need array, so upon that conversion, we will create an appropriate mask and index -

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

Sample runs -

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])

Benchmarking

Since we are concerned with performance efficiency, let's benchmark the NumPy ones, as they should be pretty efficient.

Other proposed solutions

# @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]])))

Using benchit package (few benchmarking tools packaged together; disclaimer: I am its author) to benchmark proposed solutions.

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')

With ~30% 0s :

With ~70% 0s :




回答3:


Given

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]

Code

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        

Demo

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_ones(lst_3))

Details

Slide a two-tuple window. If values are equal to each other and the target value, skip. Otherwise yield values.

An alternative, more general approach:


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




回答4:


Here is a possible solution

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)

Where arr is any list you want, and it will work with anything including strings.




回答5:


Using a while loop,

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)

another one that i found on geekforgeeks is ,

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] 


来源:https://stackoverflow.com/questions/62430679/squash-all-consecutive-ones-in-a-python-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!