2012-03-31 14 views
6

sea v una lista de númerosíndice del elemento de la lista de Python máxima

v = [3,5,2,4,8,6,1] 

Por qué el código siguiente para encontrar el elemento máximo y su índice da un error? (el objeto 'int' no es subscripible)

reduce(lambda x,y: max(x[1],y[1]), enumerate(v)) 

P.S. Sé que hay otras maneras de hacerlo, como la siguiente, pero quiero entender por qué la anterior no funciona.

max(enumerate(v), key= lambda x: x[1]) 

Epílogo

Simeón señaló que el código era causa lambda realmente mal debería haber devuelto una tupla, no un número. Entendiendo esto, mi código podría ser fijado fácilmente de la siguiente manera:

reduce(lambda x,y: x[1]<y[1] and y or x, enumerate(v)) 

que es, por cierto, un 30% más lento que

max(enumerate(v), key= lambda x: x[1]) 
+0

He votado accidentalmente para cerrar como un duplicado. No es un duplicado, sin embargo. –

Respuesta

6

Estás preguntando por qué el siguiente no funciona:

 
reduce(lambda x,y: max(x[1],y[1]), enumerate(v)) 

Veamos: su entrada es enumerate(v) que itera sobre los siguientes elementos:

 
[(0, 3), (1, 5), (2, 2), (3, 4), (4, 8), (5, 6), (6, 1)] 

Tiene la intención de reducir estos elementos con la función lambda x,y: max(x[1],y[1]). De acuerdo con the docs, reduce toma una función como entrada que se aplica a dos elementos de la iterable. Eso significa que reduce dos elementos y devuelve un valor, que es uno de los argumentos de la próxima llamada para reducir.

Eso significa x y y son tuplas. Para que lo anterior funcione, el valor de retorno de la función lambda debe ser una tupla nuevamente porque se usa nuevamente en la próxima reducción. Pero está devolviendo un número entero, el resultado de max. Es por eso que está obteniendo un error: "'int' objeto no es subscripible" porque x[1] no funciona cuando x es un número entero.

+0

Gracias! Estaba buscando el error sutil y no pude ver el grande. – mmj

2

trabajos Cómo reducir:

# type annotations: 
# reduce(lambda X,X:X, [X,X..]) -> X 

#    SAME <-- result 
#   ↗ ↖ 
#  SAME SAME] 
#  ↗ ↖ 
# SAME SAME, 
#  ↗ ↖ 
# [SAME, SAME, 

>>> reduce(lambda a,b:[a,b], [1,2,3,4]) 
[[[1, 2], 3], 4] 

Así es como se reduce con una semilla (también conocida como doblar a la izquierda) funciona:

# type annotations: 
# reduce(lambda REDU,ELEM:REDU, [ELEM,ELEM..], seed=REDU) -> REDU 

#    REDU <-- result 
#   ↗ ↖ 
#  REDU ELEM] 
#   ↗ ↖ 
#  REDU ELEM, 
#  ↗ ↖ 
# REDU ELEM, 
#  ↗ ↖ 
# REDU [ELEM, 

>>> reduce(lambda a,b:[a,b], [1,2,3,4], 'seed') 
[[[['seed', 1], 2], 3], 4] 

que desee:

maxValue,maxIndex = reduce(
    lambda p1,p2: max(p1,p2), 
    ((x,i) for i,x in enumerate(yourList)) 
) 

Lo importante a notar acerca de reduce es los tipos. * Cuando usa reducir (...) con un valor de inicialización (conocido como fold en otros idiomas), el tipo de devolución será el tipo de semilla. * Cuando usa reduce normalmente, ignora el elemento semilla. Esto funciona muy bien si todos los elementos de su lista son del mismo tipo (por ejemplo, puede reduce(operator.mul, [1,2,3]) o reduce(operator.add, [1,2,3]) bien, porque el tipo de salida reducido (int) es el mismo que el tipo de entrada no reducida (dos ints)). Sin embargo, el tipo de devolución será el mismo que el tipo del elemento de la lista.

Si los elementos son de diferentes tipos, es necesario utilizar reducir (...) en fold -mode (es decir, con una semilla con los semántica correctas). (La alternativa es en caso especial su lambda (muy fea).)

Más explícitamente, su tipo de devolución prevista es una tupla (el elemento máximo y su índice, o el reverso). Sin embargo, su función de reducción es del tipo tuple,tuple -> int. Esto no puede funcionar porque viola el contrato que reduce las demandas de su función.

Cuestiones relacionadas