переменное расширение единиц в списке python - PullRequest
1 голос
/ 18 июня 2020

У меня есть список 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)

Подсказка: решение должно быть быстрым и универсальным c для любого списка 0s и 1s и для любых offset

Ответы [ 3 ]

2 голосов
/ 18 июня 2020

Вот линейное (O (n + смещение)) временное решение:

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]
1 голос
/ 18 июня 2020

Вот решение, использующее простое понимание с фрагментом, основанным на 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]
1 голос
/ 18 июня 2020

Вы можете свернуть с массивом единиц и 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)
...