2010-11-10 16 views
8

Possible en double:
Python: map in placeExiste-t-il un équivalent sur place de 'map' en python?

J'ai une liste de chaînes que je dois désinfecter. J'ai une méthode pour les désinfectante, donc je pouvais faire:

new_list = map(Sanitize, old_list) 

mais je ne ai pas besoin de garder l'ancienne liste autour. Cela m'a fait me demander s'il y a un équivalent en place à la carte. Assez facile pour écrire une boucle for (ou une méthode de carte personnalisée sur place), mais y a-t-il quelque chose de intégré?

+0

Eh oui, c'est un dup. Je jure que j'ai cherché pour voir si cela a déjà été demandé. Apparemment, mes compétences de recherche ne sont pas encore assez bonnes. :) – Herms

+3

Pas un doublon significatif, puisque cette question n'a pas été répondue. Il est peu probable que l'on réponde aux vieilles questions (il n'y a pas moyen de "bomber" les questions), donc cela n'a pas de sens de fermer cela en tant que doublon. Fermer des dupes comme ça les condamnerait à ne jamais recevoir de réponse. –

+0

@Glen Maynard, a voté pour fermer parce que maintenant il y a une réponse. – aaronasterling

Répondre

7

La réponse est simplement: non.

Les questions de la forme "fait XXX existent" n'ont jamais tendance à obtenir une réponse directe quand la réponse est pas, donc j'ai pensé que je l'exposerais là.

La plupart des helpers et builtins d'itertools fonctionnent sur des itérateurs génériques. map, filter, compréhension de la liste, for - ils travaillent tous sur les itérateurs, ne modifiant pas le conteneur d'origine (le cas échéant). Pourquoi n'y a-t-il pas de fonctions de mutations dans cette catégorie?

Pourquoi n'y a-t-il pas de fonctions de mutation dans cette catégorie? Parce qu'il n'y a pas de moyen générique et universel d'assigner des valeurs aux conteneurs par rapport à leurs clés et valeurs. Par exemple, les itérateurs de dictée de base (for x in {}) parcourent les touches, et l'assignation à un dict utilise le résultat du dict comme paramètre à []. Les listes, en revanche, parcourent les valeurs et l'affectation utilise l'index implicite. La cohérence sous-jacente n'est pas là pour fournir des fonctions génériques comme ça, donc il n'y a rien de tel dans itertools ou dans les builtins.

Ils pourraient fournir comme méthodes de list et dict, mais actuellement ils ne le font pas. Vous aurez juste besoin de rouler le vôtre.

2

A la fin de la journée,

old_list = map(Sanitize, old_list) 

sera fait exactement ce dont vous avez besoin.

Vous pouvez objecter que la création d'un nouvel objet de liste et le nettoyage de l'ancien sont plus lents que l'utilisation d'un objet existant. En pratique, cela ne devrait presque jamais être un problème (l'allocation ponctuelle d'un morceau de mémoire est peu susceptible d'être un goulot d'étranglement, peut-être si vous le faites en boucle ou si vous avez une liste très longue, encore parierais contre vous). Rappelez-vous que de toute façon vous devez créer de nouvelles chaînes à partir de zéro dans le cadre de Sanitize et cela va être beaucoup plus cher.

A noter, comme mluebke notes, est que ces jours-ci la liste compréhensions sont considérés comme beaucoup plus « pythonique » que map (je crois map est dépréciée dans les futures versions de la langue).

Editer: Ah, je vois que vous essayez d'éditer les valeurs des arguments passés à une fonction. Je dirais assez fortement que c'est "non pythonique" et que vous devriez retourner la nouvelle liste comme l'une de vos valeurs de retour (rappelez-vous, en utilisant des tuples, vous pouvez avoir plus d'une valeur de retour).

+0

Le bit en place n'est pas vraiment un problème de récupération de place. Le problème est que j'insère cet assainissement dans du code qui ne renvoie pas de résultat. Il mute simplement la liste actuelle (il y a aussi beaucoup d'autres choses qui sont modifiées dans la liste). Donc j'ai besoin de muter ça. – Herms

5

Vous avez à boucle:

for i in range(len(old_list)): 
    old_list[i] = Sanitize(old_list[i]) 

Il n'y a rien intégré.

Comme suggéré dans les commentaires: une fonction souhaitée par l'OP:

def map_in_place(fn, l): 
    for i in range(len(l)): 
     l[i] = fn(l[i]) 

map_in_place(Sanitize, old_list) 
+0

Faites précéder votre boucle for avec 'def map_in_place (func, a_list):' et nous avons une réponse complète. (Mais 'old_list = map (Sanitize, old_list)', alors qu'il ne mute pas l'ancienne liste, semble la meilleure solution.) –

0

similaires à l'utilisation this[0] = something, vous pouvez également spécifier des tranches:

>>> x = [1, 2, 3, 4] 
>>> x[1:3] = [0, 0] 
>>> x 
[1, 0, 0, 4] 

Depuis tranches peuvent avoir des parties gauche sur (le début, l'arrêt, ou l'étape), vous pouvez changer la liste entière par quelque chose comme ceci:

>>> x = [1, 2, 3, 4] 
>>> x[:] = [4, 5, 6] 
>>> x 
[4, 5, 6] 

Ceci (comme vu ci-dessus) est capable de changer même la longueur de la liste. Comme on peut le voir ci-dessous, cela change en effet l'objet réel, pas redéfinir la variable:

>>> x = [1, 2, 3, 4] 
>>> y = x 
>>> x[:] = [3, 4] 
>>> y 
[3, 4] 

Il ne doit pas nécessairement être une liste à l'extrémité droite de la mission. Tout ce qui est itérable peut être de ce côté. En fait, vous pourriez même avoir un générateur:

>>> x = ["1", "2", "3", "4"] 
>>> x[:] = (int(y) for y in x) 
>>> x 
[1, 2, 3, 4] 

ou les retours de map() (une liste en Python 2, un objet map en Python 3):

>>> x = ["1", "2", "3", "4"] 
>>> x[:] = map(int, x)