2012-05-31 15 views
72

digamos que tenemos una función de añadir la siguiente manera¿Cómo hacer múltiples argumentos para mapear la función donde uno permanece igual en python?

def add(x, y): 
    return x + y 

queremos aplicar la función de mapa para una variedad

map(add, [1, 2, 3], 2) 

La semántica es que quiero añadir 2 a la cada elemento de la matriz. Pero la función map también requiere una lista en el tercer argumento.

Nota: Pongo el ejemplo de agregar por simplicidad. Mi función original es mucho más complicada. Y, por supuesto, la opción de configurar el valor predeterminado de y en la función de agregar está fuera de cuestión ya que se cambiará para cada llamada.

+8

esto es exactamente lo mismo que en Lisp: 'map (add, [1,2,3], [2] * 3)' en general 'map' toma una función como primer argumento, y si esta función toma el argumento ** K **, tiene que seguir con ** K ** iterable: 'addTriple (a, b, c) -> map (addTriple, [...], [...], [. ..]) ' – watashiSHUN

Respuesta

105

Una opción es una lista por comprensión:

[add(x, 2) for x in [1, 2, 3]] 

Más opciones:

a = [1, 2, 3] 

import functools 
map(functools.partial(add, y=2), a) 

import itertools 
map(add, a, itertools.repeat(2, len(a))) 
+1

yup, pero ¿qué tan rápido es en comparación con la función de mapa? – Shan

+0

@Shan: muy similar, especialmente si 'add()' es una función no trivial –

+0

@Shan: las comprensiones de la lista son aproximadamente un 15% más rápidas en mi caja. –

30

Use una lista de comprensión.

[x + 2 for x in [1, 2, 3]] 

Si realmente, realmente, realmente desea utilizar map, darle una función anónima como primer argumento:

map(lambda x: x + 2, [1,2,3]) 
12

Si lo tiene disponible, consideraría usar numpy. Es muy rápido para estos tipos de operaciones:

>>> import numpy 
>>> numpy.array([1,2,3]) + 2 
array([3, 4, 5]) 

Esto es suponiendo que su aplicación real está haciendo operaciones matemáticas (que se pueden vectorizar).

+4

Esto supone que su aplicación real está haciendo operaciones matemáticas * que pueden vectorizarse usando NumPy. * –

+0

sí, buena captura, actualizado – jterrace

8

Si realmente necesita usar la función de mapa (como mi asignación de clase aquí ...), podría usar una función de contenedor con 1 argumento, pasando el resto al original en su cuerpo; es decir:

extraArguments = value 
def myFunc(arg): 
    # call the target function 
    return Func(arg, extraArguments) 


map(myFunc, itterable) 

sucio & feo, todavía lo hace el truco

+1

Un cierre, creo que esto agrega algo más uno. Similar a una función parcial, como la respuesta aceptada tiene. –

+1

'myFunc' necesita' devolver Func (arg, extraArguments) ' –

+0

Estoy corregido @ PM2Ring, eso es cierto; actualizado el código – Todor

26

Los documentos indican explícitamente que este es el principal uso de itertools.repeat:

Hacer un iterador que vuelve objeto una y otra vez. Se ejecuta indefinidamente a menos que se especifique el argumento de tiempos. Se utiliza como argumento en map() para los parámetros invariables de la función llamada. También se usa con zip() para crear una parte invariable de un registro de tupla.

Y no hay razón para pasar len([1,2,3]) como el argumento times; map se detiene tan pronto como se consume el primer iterable, por lo que un iterable infinita está perfectamente bien:

>>> from operator import add 
>>> from itertools import repeat 
>>> list(map(add, [1,2,3], repeat(4))) 
[5, 6, 7] 

De hecho, esto es equivalente al ejemplo de repeat en la documentación:

>>> list(map(pow, range(10), repeat(2))) 
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 

Esto hace para una buena solución de lenguaje funcional perezoso que también es perfectamente legible en términos de iterador de Python.

+0

+1 Esta debería ser la respuesta aceptada. Se extiende a cualquier cantidad de parámetros, por supuesto, con algunas listas constantes y otras o generadores. Ejemplo: 'def f (x, y, z): \\ return '.'. Join ([x, y, z])' y luego: 'list (map (f, list ('abc'), repeat ('foo'), list ('defgh'))) 'devuelve' ['a.foo.d', 'b.foo.e', 'c.foo.f'] '. –

+4

En Python 2, es necesario proporcionar el argumento de longitud para 'repeat()', ya que 'map()' se ejecutará hasta que el _longest_ iterator se agote en esa versión de Python, rellenando 'None' para todos los valores perdidos. Decir que "no hay razón" para pasar el parámetro es incorrecto. –

0

Otra opción es:

results = [] 
for x in [1,2,3]: 
    z = add(x,2) 
    ... 
    results += [f(z,x,y)] 

Este formato es muy útil cuando se llama a múltiples funciones.

6

veces me resolvieron situaciones similares (como el uso de pandas.apply método) usando closures

Con el fin de utilizarlos, se define una función que define de forma dinámica y devuelve un contenedor para su función, por lo que efectivamente uno de los parámetros de una constante.

Algo como esto:

def add(x, y): 
    return x + y 

def add_constant(y): 
    def f(x): 
     return add(x, y) 
    return f 

Entonces, add_constant(y) devuelve una función que se puede utilizar para agregar y a cualquier valor dado:

>>> add_constant(2)(3) 
5 

que le permite utilizarlo en cualquier situación en la que los parámetros se dan de a uno por vez:

>>> map(add_constant(2), [1,2,3]) 
[3, 4, 5] 

edición

Si no quieren tener que escribir la función de cierre de algún otro lugar, siempre se tiene la posibilidad de construir sobre la marcha usando una función lambda:

>>> map(lambda x: add(x, 2), [1, 2, 3]) 
[3, 4, 5] 
1

pasar múltiples argumentos a una función map.

def q(x,y): 
    return x*y 

print map (q,range(0,10),range(10,20)) 

Aquí q es la función con el argumento de que múltiples del mapa() llamadas. Asegúrese de que, la longitud de ambos los rangos, es decir,

len (range(a,a')) and len (range(b,b')) are equal. 
4

Mapa puede contener varios argumentos, la forma estándar es

map(add, a, b) 

En su pregunta, debe ser

map(add, a, [2]*len(a)) 
5

El la respuesta correcta es más simple de lo que piensasBasta con hacer :

map(add, [(x, 2) for x in [1,2,3]]) 

y cambiar la aplicación del complemento de tomar una tupla es decir

def add(t): 
    x, y = t 
    return x+y 

Esto puede manejar cualquier caso de uso complicado donde ambas añadir parámetros son dinámicos.

Cuestiones relacionadas