2013-01-16 3 views
7

J'ai une liste: mylist = [0, 0, 0, 0, 0]Remplacer des éléments sélectionnés dans une liste en Python

Je veux seulement remplacer les éléments sélectionnés, disent les première, deuxième et quatrième par un numéro commun, A = 100.

Une façon de le faire:

mylist[:2] = [A]*2 
mylist[3] = A 
mylist 
[100, 100, 0, 100, 0] 

Je cherche une doublure ou une méthode plus facile de le faire. Une réponse plus générale et plus flexible est préférable.

+0

Comment cela? mylist [: 2], mylist [3] = [A] * 2, A –

Répondre

7

D'autant plus que vous remplacez un morceau considérable de la list, je ferais ce immuablement:

mylist = [100 if i in (0, 1, 3) else e for i, e in enumerate(mylist)] 

Il est intentionnel en Python qui fait une nouvelle list est un one-liner, tout unmuternécessite une boucle explicite. Habituellement, si vous ne savez pas lequel vous voulez, vous voulez le nouveau list. (Dans certains cas, il est plus lent ou plus compliqué, ou vous avez un autre code qui fait référence au même list et doit le voir muté, ou quoi que ce soit, c'est pourquoi c'est "habituellement" plutôt que "toujours".)

Si vous voulez faire plus d'une fois, je l'envelopper dans une fonction, comme la volatilité suggère:

def elements_replaced(lst, new_element, indices): 
    return [new_element if i in indices else e for i, e in enumerate(lst)] 

personnellement, je faire probablement un générateur de sorte qu'il donne une itération au lieu de retourner une liste, même si je n'en aurai jamais besoin, juste parce que je suis stupide de cette façon. Mais si vous avez réellement faire besoin:

myiter = (100 if i in (0, 1, 3) else e for i, e in enumerate(mylist)) 

Ou:

def elements_replaced(lst, new_element, indices): 
    for i, e in enumerate(lst): 
     if i in indices: 
      yield new_element 
     else: 
      yield e 
+0

Bonne explication concernant la nouvelle liste et la mutation. – elwc

+0

Parfois, le 'valarray :: gslice' me manque – Abhijit

+0

@Abhijit: Eh bien, presque tous les cas où' valarray' a du sens en C++, 'numpy' a du sens en Python - et le découpage en longueur de' numpy' est encore plus simple que 'gslice' pour presque tous les cas. Par exemple, voir la réponse de mgilson à cette question. (Bien sûr, "presque tous" et "presque tous" ne sont pas exactement les mêmes que "tous" et "tous" ... mais il est rare que je me retrouve à écrire du code 'numpy' et à manquer une fonction C++ ...) – abarnert

0

Est-ce ce que vous cherchez? Faites une liste des index que vous souhaitez modifier, puis parcourez cette liste pour modifier les valeurs.

els_to_replace = [0, 1, 3] 

mylist = [0, 0, 0, 0, 0] 

for index in els_to_replace: 
    mylist[index] = 100 


mylist 
Out[9]: [100, 100, 0, 100, 0] 
2
def replace_element(lst, new_element, indices): 
    for i in indices: 
     lst[i] = new_element 
    return lst 

Il est certainement une solution plus générale, pas un one-liner bien. Par exemple, dans votre cas, vous appelez:

mylist = replace_element(mylist, 100, [0, 1, 3]) 
+0

+1. En plus d'être plus général, je pense que c'est la façon la plus facile de faire le remplacement mutable, malgré (ou, probablement, à cause de) ne pas être un one-liner. – abarnert

1

Numpy soutient si vous n'êtes pas opposé à l'aide d'un np.ndarray:

>>> a = np.zeros(5) 
>>> a[[0,1,3]] = 100 
>>> a 
array([ 100., 100., 0., 100., 0.]) 
+0

+1. Même si cela ne répond pas directement à la question de l'OP (et je ne suis pas sûr que ce ne soit pas le cas), chaque fois que vous vous trouvez face à des séquences de chiffres et que quelque chose semble plus difficile que "suis-je opposé à l'utilisation d'un" np.ndarray "ici?" – abarnert

0

pas un grand fan de celui-ci, mais vous pouvez essayer cela (même si je pense que tous les ci-dessus sont beaucoup plus concis et facile à lire):

In [22]: from operator import setitem 

In [23]: mylist = [0, 0, 0, 0, 0] 

In [24]: indeces_to_replace = [0, 1, 3] 

In [25]: _ = map(lambda x: setitem(mylist, x, 100), indeces_to_replace) 

In [26]: mylist 
Out[26]: [100, 100, 0, 100, 0] 

Mis à part la lisibilité douteuse et la nécessité d'une importation, @abarnert a souligné quelques questions supplémentaires, à savoir que 012.369.crée toujours une liste inutile (qui est rejetée avec le _ mais créé néanmoins) et que cela ne fonctionnera pas dans Python 3 car mapreturns an iterator dans Python 3.x. Vous pouvez utiliser le module six pour simuler le comportement de map dans Python 3.x à partir de Python 2.x, et en combinaison avec collections.deque (encore une fois comme suggéré par @abarnert), vous pouvez obtenir la même sortie sans créer la liste supplémentaire en mémoire car un deque pouvant contenir un maximum de 0 éléments rejettera tout ce qu'il reçoit de l'itérateur map (notez qu'avec six, map est simulé en utilisant itertools.imap).

Encore une fois, il n'y a absolument pas besoin d'utiliser ce jamais - toutes les solutions ci-dessus/dessous est mieux :)

In [1]: from collections import deque 

In [2]: from six.moves import map 

In [3]: from operator import setitem 

In [4]: mylist = [0, 0, 0, 0, 0] 

In [5]: indeces_to_replace = [0, 1, 3] 

In [6]: deque(map(lambda x: setitem(mylist, x, 100), indeces_to_replace), maxlen=0) 
Out[6]: deque([], maxlen=0) 

In [7]: mylist 
Out[7]: [100, 100, 0, 100, 0] 
+0

problème avec ceci est que dans Python 3, cela ne fonctionne pas, parce que vous revenez juste un itérateur que vous n'érigez jamais. Le plus petit problème est que dans Python 2, il construit une liste dont vous n'avez pas besoin. Vous pouvez résoudre le premier problème en faisant explicitement 'list (map (...))'. Ou vous pouvez résoudre les deux en utilisant 'six.map' et en passant le résultat à une fonction' iter_discard', que vous pouvez implémenter comme 'collections.deque (it, max_size = 0)'. Ce qui est beaucoup plus pensé que vous ne devriez jamais mettre dans une solution que vous n'étiez pas un grand fan de la première place, bien sûr ... – abarnert

+0

@abarnert Belated +1 à votre réponse (toujours aussi informatif), et de grands points concernant cette implémentation (jamais pensé à passer les résultats de 'map' à une fonction' iter_discard'). Je vais ajouter dans une mise à jour pour l'amour de la postérité, et merci comme toujours pour l'info utile :) – RocketDonkey

+0

J'aimerais vraiment que 'iter_discard' fasse partie de la bibliothèque 3.x standard. L'argument contre cela était que cela voudrait encourager les gens à utiliser 'map' pour les effets secondaires au lieu des résultats (et, si vous le voulez vraiment, l'astuce' deque' a été ajouté à la documentation de 'itertools' quelque part). Je peux l'acheter ... mais pour ce genre de questions, les gens le font quand même (et veulent ensuite "chronométrer" les résultats avec chaque version de Python qu'ils peuvent trouver). – abarnert

0

J'aime une compréhension de la liste:

[100 if index in [1, 4] else 0 for index, x in enumerate(mylist) ] 
Questions connexes