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?
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
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))
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', '']
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.
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)
[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?
>>> 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]
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()
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.