python 列表中的变量扩展
variable expansion of ones in python list
我有一个 python 可变长度列表,其中填充了 0s
和 1s
。
我想创建一个新列表,其中所有 1s
都扩展了某个 offset
。
示例:
offset = 1
l1 = [0,0,1,0]
l1_new = l[0,1,1,1]
l2 = [1,0,0,0,1,0,1,0,0]
l2_new = [1,1,0,1,1,1,1,1,0]
我的解决方案代码不是很快,也没有使用任何 numpy/向量化/按位运算。但我想其中一些方法应该适用于此。
offset = 1
l_old = [0,0,1,0]
l_new = []
for i,l in enumerate(l_old):
hit = False
for o in range(offset+1)[1:]:
if (i+o<len(l_old) and l_old[i+o]) or (i>0 and l_old[i-o]):
hit = True
break
if hit or l_old[i]:
l_new.append(1)
else:
l_new.append(0)
Hint: The solution should be fast and generic for any list of 0s
and 1s
and for any offset
您可以convolve with an array of ones, and clip
结果:
def expand1s(a, offset):
w = offset*2 +1
return np.convolve(a, np.ones(w), mode='same').clip(0,1)
expand1s(l1, 1)
# array([0., 1., 1., 1.])
expand1s(l2, 1)
# array([1., 1., 0., 1., 1., 1., 1., 1., 0.])
或者我们还有skimage.morphology.binary_dilation
:
from skimage.morphology import binary_dilation
a = np.array(l2)
w = offset*2 +1
binary_dilation(a, np.ones(w)).view('i1')
# array([1, 1, 0, 1, 1, 1, 1, 1, 0], dtype=int8)
这是一个使用基于 offset
:
的切片的简单理解的解决方案
>>> def expand_ones(old: list, offset: int) -> list:
... return [1 if any(
... old[max(0, i-offset):min(len(old), i+offset+1)]
... ) else 0 for i in range(len(old))]
...
>>> expand_ones([1, 0, 0, 0, 1, 0, 1, 0, 0], 1)
[1, 1, 0, 1, 1, 1, 1, 1, 0]
>>> expand_ones([1, 0, 0, 0, 1, 0, 1, 0, 0], 2)
[1, 1, 1, 1, 1, 1, 1, 1, 1]
这里是一个线性(O(n+offset))时间的解:
import numpy as np
def symm_dil(a,hw):
aux = np.zeros(a.size+2*hw+1,a.dtype)
aux[:a.size] = a
aux[2*hw+1:] -= a
return np.minimum(aux.cumsum(),1)[hw:-hw-1]
#example
rng = np.random.default_rng()
a = rng.integers(0,2,10)
print(a)
print(symm_dil(a,2))
示例输出:
[0 0 0 1 0 0 0 0 0 1]
[0 1 1 1 1 1 0 1 1 1]
我有一个 python 可变长度列表,其中填充了 0s
和 1s
。
我想创建一个新列表,其中所有 1s
都扩展了某个 offset
。
示例:
offset = 1
l1 = [0,0,1,0]
l1_new = l[0,1,1,1]
l2 = [1,0,0,0,1,0,1,0,0]
l2_new = [1,1,0,1,1,1,1,1,0]
我的解决方案代码不是很快,也没有使用任何 numpy/向量化/按位运算。但我想其中一些方法应该适用于此。
offset = 1
l_old = [0,0,1,0]
l_new = []
for i,l in enumerate(l_old):
hit = False
for o in range(offset+1)[1:]:
if (i+o<len(l_old) and l_old[i+o]) or (i>0 and l_old[i-o]):
hit = True
break
if hit or l_old[i]:
l_new.append(1)
else:
l_new.append(0)
Hint: The solution should be fast and generic for any list of
0s
and1s
and for anyoffset
您可以convolve with an array of ones, and clip
结果:
def expand1s(a, offset):
w = offset*2 +1
return np.convolve(a, np.ones(w), mode='same').clip(0,1)
expand1s(l1, 1)
# array([0., 1., 1., 1.])
expand1s(l2, 1)
# array([1., 1., 0., 1., 1., 1., 1., 1., 0.])
或者我们还有skimage.morphology.binary_dilation
:
from skimage.morphology import binary_dilation
a = np.array(l2)
w = offset*2 +1
binary_dilation(a, np.ones(w)).view('i1')
# array([1, 1, 0, 1, 1, 1, 1, 1, 0], dtype=int8)
这是一个使用基于 offset
:
>>> def expand_ones(old: list, offset: int) -> list:
... return [1 if any(
... old[max(0, i-offset):min(len(old), i+offset+1)]
... ) else 0 for i in range(len(old))]
...
>>> expand_ones([1, 0, 0, 0, 1, 0, 1, 0, 0], 1)
[1, 1, 0, 1, 1, 1, 1, 1, 0]
>>> expand_ones([1, 0, 0, 0, 1, 0, 1, 0, 0], 2)
[1, 1, 1, 1, 1, 1, 1, 1, 1]
这里是一个线性(O(n+offset))时间的解:
import numpy as np
def symm_dil(a,hw):
aux = np.zeros(a.size+2*hw+1,a.dtype)
aux[:a.size] = a
aux[2*hw+1:] -= a
return np.minimum(aux.cumsum(),1)[hw:-hw-1]
#example
rng = np.random.default_rng()
a = rng.integers(0,2,10)
print(a)
print(symm_dil(a,2))
示例输出:
[0 0 0 1 0 0 0 0 0 1]
[0 1 1 1 1 1 0 1 1 1]