listas - replace python
Reemplazo periĆ³dico de valores en una lista. (8)
Supongamos que tengo la siguiente lista en Python:
my_list = [10] * 95
Dado n
, quiero reemplazar cualquier otro elemento m
con cero en mi lista, manteniendo los siguientes n
elementos.
Por ejemplo, si n = 3
y m = 2
, quiero que mi lista se vea como:
[10, 10, 10, 0, 0, 10, 10, 10 ,0, 0, ..., 10, 10, 10 , 0, 0]
Si no puede llenarse a la perfección, como es el caso con n = 4
y m = 2
, entonces está bien si mi lista se ve así:
[10, 10, 10, 10, 0, 0, ..., 10, 10, 10, 10, 0]
¿Cómo debo tratar de resolver este problema?
¿Qué tal esto?
my_list = [10] * 95
n = 3
m = 2
for i in range(n, len(my_list)-1, n+m):
my_list[i:i+m] = [0]*m
print(my_list)
Editar
Descubrí que el código anterior cambia la longitud de la lista resultante en algunos casos.
>>> a = [1,2,3]
>>> a[2:4] = [0] * 2
>>> a
[1, 2, 0, 0]
Por lo tanto, la longitud debe ser restaurada de alguna manera.
my_list = [10] * 95
cp_list = list(my_list)
n = 3
m = 5
for i in range(n, len(my_list)-1, n+m):
cp_list[i:i+m] = [0]*m
cp_list = cp_list[:len(my_list)]
print(cp_list)
Esto funcionó para mí:
list = [10] * 95
n = 4
m = 2
amask = np.tile(np.concatenate((np.ones(n),np.zeros(m))),int((len(list)+1)/(n+m)))[:len(list)]
list = np.asarray(list)*amask
que produce:
array([10., 10., 10., 10., 0., 0., 10., 10., 10., 10., 0., 0., 10.,
10., 10., 10., 0., 0., 10., 10., 10., 10., 0., 0., 10., 10.,
10., 10., 0., 0., 10., 10., 10., 10., 0., 0., 10., 10., 10.,
10., 0., 0., 10., 10., 10., 10., 0., 0., 10., 10., 10., 10.,
0., 0., 10., 10., 10., 10., 0., 0., 10., 10., 10., 10., 0.,
0., 10., 10., 10., 10., 0., 0., 10., 10., 10., 10., 0., 0.,
10., 10., 10., 10., 0., 0., 10., 10., 10., 10., 0., 0., 10.,
10., 10., 10., 0.])
El código toma n
y construye una máscara de unos y ceros con una longitud que coincide con su list
inicial usando la función np.tile
. Después, simplemente multiplica la máscara en la lista y obtiene los ceros donde quieres que estén. También debe ser flexible a diferentes longitudes de la lista y una elección (casi) arbitraria de n
y m
.
Puede convertir la matriz de nuevo a una lista si lo desea.
Otra posibilidad más, esta vez con enumerate
:
[x * (i % (n + m) < n) for i, x in enumerate(my_list)]
Utiliza el hecho de que False
y True
son iguales a 0
y 1
en Python (ver here ).
Como beneficio adicional, funciona bien incluso si la lista no es constante:
>>> n = 4
>>> m = 2
>>> my_list = range(20)
>>> [x * (i % (n+m) < n) for i, x in enumerate(my_list)]
[0, 1, 2, 3, 0, 0, 6, 7, 8, 9, 0, 0, 12, 13, 14, 15, 0, 0, 18, 19]
Si la lista contiene cadenas, las reemplaza con una cadena vacía en lugar de 0
:
>>> my_list = ''abcdefghijk''
>>> [x * (i % (n+m) < n) for i, x in enumerate(my_list)]
[''a'', ''b'', ''c'', ''d'', '''', '''', ''g'', ''h'', ''i'', ''j'', '''']
Podría usar itertools.cycle
para crear una secuencia infinita de [10, 10, 10, 0, 0]
y luego tomar los primeros 95 elementos de esa secuencia con itertools.islice
:
n = 3
m = 2
pattern = [10] * n + [0] * m
my_list = list(itertools.islice(itertools.cycle(pattern), 95))
También en la familia de itertools, puede repeat
un patrón deseado:
Dado
import itertools as it
m, n = 2, 3
p = n + 1
Código
pattern = it.repeat([10] * n + [0] * m)
res = list(it.islice(it.chain.from_iterable(pattern), None, 95))
print(res)
# [10, 10, 10, 10, 0, 0, 10, 10, 10, 10, 0, 0, ... 10, 10, 10, 10, 0, 0]
pattern = it.repeat([10] * p + [0] * m)
res = list(it.islice(it.chain.from_iterable(pattern), None, 95))
print(res)
# [10, 10, 10, 10, 0, 0, 10, 10, 10, 10, 0, 0, ... 10, 10, 10, 10, 0]
Prueba
assert len(res) == 95
Sin embargo, la solución de itertools.cycle
@ Aran-Fey es más limpia ya que no requiere encadenamiento.
numpy
puede hacer esto bastante concisamente, también!
a = np.array(my_list).reshape(-1, n + m)
a[:, n:] = 0
result = a.ravel().tolist()
my_list = [10] * 95
n = 3
m = 2
for i in range(m):
my_list[n+i::m+n] = [0] * len(my_list[n+i::m+n])
Esto solo necesita m
tareas para hacer el trabajo (y m
probablemente sea pequeño).
Si realmente tiene dos valores posibles (por ejemplo, 10 y 0), puede hacerlo aún más simple:
my_list = [ 10 if i % (n+m) < n else 0 for i in range(95) ]
Pero eso se repite en Python en todo el rango de 95, por lo que probablemente no sea muy rápido.
Un poco más complejo pero probablemente más eficiente (especialmente para listas grandes y valores grandes para n
) sería esto:
my_list = (([ 10 ] * n + [ 0 ] * m) * (95 // (n + m) + 1))[:95]
Pero construye internamente muchas listas, así que depende de las pruebas para averiguar si esto es eficiente en su caso. (También se debe tener en cuenta el consumo de memoria para listas grandes).
Si puedes usar numpy
(un poco fuera de la pregunta, pero dado que está muy extendido):
my_list = (np.arange(95) % (n+m) < n) * 10
[j for i in [[input_num] * n + [0] * m for x in range(int(num / (m + n)) + 1)][:num] for j in i]
¿Tal vez?
Resultado
>>> num, input_num, m, n=95, 10, 2, 3
>>> [j for i in [[input_num] * n + [0] * m for x in range(int(num / (m + n)) + 1)][:num] for j in i]
[10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0 , 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0]