2010-11-10 18 views
8

Duplicar posible:
Python: map in place¿Hay un equivalente in situ para 'mapa' en python?

que tiene una lista de cadenas que necesito para desinfectar. Tengo un método para desinfectar ellos, por lo que sólo podía hacer:

new_list = map(Sanitize, old_list) 

pero yo no necesito para mantener la lista de edad alrededor. Esto me hizo preguntarme si hay un equivalente en el lugar al mapa. Es lo suficientemente fácil como para escribir un bucle for (o un método de mapa in situ personalizado), pero ¿hay algo incorporado?

+0

Sí, este es un DUP. Juro que he buscado para ver si esto ya se ha preguntado. Aparentemente mis habilidades de búsqueda aún no son lo suficientemente buenas. :) – Herms

+3

No es un duplicado significativo, ya que esa pregunta no fue respondida. Es poco probable que se respondan las viejas preguntas (no hay forma de "responder" a las preguntas), por lo que no tiene sentido cerrar esto como un duplicado. Cerrar a los incautos de esa manera los condenaría a nunca ser respondidos. –

+0

@Glenn Maynard, votó para cerrar porque ahora hay una respuesta. – aaronasterling

Respuesta

7

La respuesta es simple: no.

Las preguntas del formulario "¿existe XXX?" Nunca suelen responderse directamente cuando la respuesta es no, así que pensé que lo pondría allí.

La mayoría de los auxiliares e implementadores de itertools operan en iteradores genéricos. map, filter, listas de comprensión, for --todos funcionan en iteradores, no modificando el contenedor original (si lo hay).

¿Por qué no hay funciones mutantes en esta categoría? Porque no existe una forma genérica y universal de asignar valores a los contenedores con respecto a sus claves y valores. Por ejemplo, los iteradores dict básicos (for x in {}) iteran sobre las claves, y la asignación a un dict usa el resultado del dict como parámetro para []. Las listas, por otro lado, iteran sobre los valores , y la asignación utiliza el índice implícito. La consistencia subyacente no está ahí para proporcionar funciones genéricas como esta, por lo que no hay nada como esto en itertools o en los builtins.

Podrían proporcionarlo como métodos de list y dict, pero actualmente no es así. Solo tendrás que hacer tu propio.

2

Al final del día,

old_list = map(Sanitize, old_list) 

obtendrá hecho exactamente lo que necesita.

Puede objetar que la creación de un nuevo objeto de la lista y la recolección de la basura de la anterior es más lenta que con una existente. En la práctica, esto casi nunca debería ser un problema (asignar como una sola vez un pedazo de memoria es poco probable que sea un cuello de botella, tal vez si estás haciendo esto en un bucle o tienes una lista masivamente larga, podrías probar el benchmarking, pero aún apostaría contra ti). Recuerde que, en cualquier caso, debe crear nuevas cadenas desde cero como parte de Sanitize y eso va a ser mucho más costoso.

A tener en cuenta, como mluebke notas, es que estas listas por comprensión días se consideran mucho más "Pythonic" que map (creo map está en desuso en las futuras versiones de la lengua).

Editar: Ah, veo que estás tratando de editar los valores de los argumentos pasados ​​a una función. Creo firmemente que esto es "antipático" y que debe devolver la nueva lista como uno de sus valores de retorno (recuerde, usando las tuplas puede tener más de un valor de retorno).

+0

El bit in situ no es realmente un problema de recolección de basura. El problema es que estoy insertando este saneamiento dentro de un código que no devuelve un resultado. Simplemente muta la lista actual (hay muchas otras cosas que también se modifican en la lista). Entonces necesito mutar eso. – Herms

5

Tienes que bucle:

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

No hay nada incorporado.

Como se sugiere en los comentarios: una función tan deseados por el 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

Preceda su bucle for con 'def map_in_place (func, a_list):' y tenemos una respuesta completa. (Pero 'old_list = map (Sanitize, old_list)', aunque no mute la lista anterior, parece ser la mejor solución). –

0

Al igual que el uso de this[0] = something, también puede especificar rebanadas:

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

Desde rebanadas pueden tener partes que se dejaron fuera (inicio, finalización o paso), puede cambiar toda la lista por algo como esto:

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

Esto (como se ve arriba) es capaz de cambiar incluso la longitud de la lista. Como se verá más adelante, esto es, en efecto cambiando el objeto real, no la redefinición de la variable:

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

No necesariamente tiene que ser una lista en el extremo derecho de la asignación. Cualquier cosa que sea iterable puede estar en ese lado. De hecho, incluso se podría tener un generador:

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

o las devoluciones de map() (una lista en Python 2; un objeto map en Python 3):

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