web-dev-qa-db-fra.com

Remplacement périodique des valeurs dans une liste

Supposons que j'ai la liste suivante en Python:

my_list = [10] * 95

Étant donné n, je souhaite remplacer tout autre élément m par zéro dans ma liste, tout en conservant les éléments n suivants. 

Par exemple, si n = 3 et m = 2, je souhaite que ma liste se présente comme suit:

[10, 10, 10, 0, 0, 10, 10, 10 ,0, 0, ..., 10, 10, 10 , 0, 0]

Si cela ne peut pas être rempli parfaitement, comme c'est le cas avec n = 4 et m = 2, alors ça va si ma liste ressemble à ceci:

[10, 10, 10, 10, 0, 0, ..., 10, 10, 10, 10, 0]

Comment devrais-je essayer de résoudre ce problème?

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

Ceci nécessite juste des assignations m pour faire le travail (et m est probablement petit).

Si vous ne disposez que de deux valeurs possibles (par exemple 10 et 0), vous pouvez le faire encore plus simplement:

my_list = [ 10 if i % (n+m) < n else 0 for i in range(95) ]

Mais cela se répète en Python sur toute la plage de 95, ce n’est donc probablement pas très rapide.

Un peu plus complexe mais probablement plus efficace (surtout pour les listes énormes et les valeurs importantes pour n et m) serait la suivante:

my_list = (([ 10 ] * n + [ 0 ] * m) * (95 // (n + m) + 1))[:95]

Mais il construit en interne de nombreuses listes. Il vous incombe donc de vérifier si cela est efficace dans votre cas. (La consommation de mémoire doit également être prise en compte pour les grandes listes.)

Si vous pouvez utiliser numpy (un peu en dehors de la question, mais puisque c'est répandu):

my_list = (np.arange(95) % (n+m) < n) * 10
27
Alfe

Vous pouvez utiliser itertools.cycle pour créer une séquence infinie de [10, 10, 10, 0, 0] puis prendre les 95 premiers éléments de cette séquence avec itertools.islice :

n = 3
m = 2

pattern = [10] * n + [0] * m
my_list = list(itertools.islice(itertools.cycle(pattern), 95))
28
Aran-Fey

Encore une autre possibilité, cette fois avec enumerate :

[x * (i % (n + m) < n) for i, x in enumerate(my_list)]

Il utilise le fait que False et True sont égaux à 0 et 1 en Python (voir ici ).

En prime, cela fonctionne bien même si la liste n'est pas 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 liste contient des chaînes, elle les remplace par une chaîne vide au lieu 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', '']
7
Eric Duminil

Cela a fonctionné pour moi:

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

qui produit:

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

Le code prend n et m et construit un masque de uns et de zéros avec une longueur correspondant à votre list initiale en utilisant la fonction np.tile. Ensuite, il vous suffit de multiplier le masque sur la liste et d’obtenir les zéros où vous le souhaitez. Il devrait également être modulable pour différentes longueurs de la liste et un choix (presque) arbitraire de n et m.

Vous pouvez convertir le tableau en liste si vous le souhaitez.

6
Shintlor

Que dis-tu de ça?

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)

Modifier 

J'ai découvert que le code ci-dessus change la longueur de la liste résultante dans certains cas.

>>> a = [1,2,3]
>>> a[2:4] = [0] * 2
>>> a
[1, 2, 0, 0]

Ainsi, la longueur devrait être restaurée en quelque sorte.

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)
4
klim
[j for i in [[input_num] * n + [0] * m for x in range(int(num / (m + n)) + 1)][:num] for j in i]

Peut être?

Résultat

>>> 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]
3
Moonsik Park

numpy peut faire cela de manière très concise, aussi!

a = np.array(my_list).reshape(-1, n + m)
a[:, n:] = 0
result = a.ravel().tolist()
3
timgeb

Toujours dans la famille itertools, vous pouvez repeat un motif souhaité:

Donné

import itertools as it


m, n = 2, 3
p = n + 1    

Code

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]

Tester

assert len(res) == 95

Cependant, la solution itertools.cycle de @ Aran-Fey est plus propre car elle ne nécessite pas de chaînage.

0
pylang