2010-10-23 40 views

Respuesta

59
map(max, zip(*alist)) 

Esta primera abre la cremallera de su lista, a continuación, busca el máximo para cada posición tupla

>>> alist = [(1,3),(2,5),(2,4),(7,5)] 
>>> zip(*alist) 
[(1, 2, 2, 7), (3, 5, 4, 5)] 
>>> map(max, zip(*alist)) 
[7, 5] 
>>> map(min, zip(*alist)) 
[1, 3] 

Esto también funciona para las tuplas de cualquier longitud en una lista.

+1

Una buena respuesta, todavía tengo que aprender a usar el código postal, etc., tan elegantemente – pyfunc

+1

, ¿puedes decir algo más sobre lo que * delante de alist hace? zip se comporta REALMENTE de manera diferente sin * allí ... – Andrew

+5

@Andrew Claro, el '*' empalma la lista en los argumentos de la función. La mejor manera de entender esto es con el ejemplo: 'f (* [1, 2, 3])' es exactamente lo mismo que 'f (1, 2, 3)', así que 'zip (* [(1, 3) , (2, 5), (2, 4), (7, 5)]) 'es lo mismo que' zip ((1, 3), (2, 5), (2, 4), (7, 5)) 'que devuelve' [(1, 2, 2, 7), (3, 5, 4, 5)] '. Para obtener detalles completos y sangrientos, consulte la [documentación] (http://docs.python.org/2/reference/expressions.html#calls) – cobbal

8
>>> from operator import itemgetter 
>>> alist = [(1,3),(2,5),(2,4),(7,5)] 
>>> min(alist)[0], max(alist)[0] 
(1, 7) 
>>> min(alist, key=itemgetter(1))[1], max(alist, key=itemgetter(1))[1] 
(3, 5) 
3

Un enfoque generalizado sería algo como esto:

alist = [(1,6),(2,5),(2,4),(7,5)] 

temp = map(sorted, zip(*alist)) 
min_x, max_x, min_y, max_y = temp[0][0], temp[0][-1], temp[1][0], temp[1][-1] 

Para Python 3, que había necesidad de cambiar la línea que crea temp a:

temp = tuple(map(sorted, zip(*alist))) 

La idea puede ser resumido en una función que funciona tanto en Python 2 como en 3:

from __future__ import print_function 
try: 
    from functools import reduce # moved into functools in release 2.6 
except ImportError: 
    pass 

# readable version 
def minmaxes(seq): 
    pairs = tuple() 
    for s in map(sorted, zip(*seq)): 
     pairs += (s[0], s[-1]) 
    return pairs 

# functional version 
def minmaxes(seq): 
    return reduce(tuple.__add__, ((s[0], s[-1]) for s in map(sorted, zip(*seq)))) 

alist = [(1,6), (2,5), (2,4), (7,5)] 
min_x, max_x, min_y, max_y = minmaxes(alist) 
print(' '.join(['{},{}']*2).format(*minmaxes(alist))) # 1,7 4,6 

triplets = [(1,6,6), (2,5,3), (2,4,9), (7,5,6)] 
min_x, max_x, min_y, max_y, min_z, max_z = minmaxes(triplets) 
print(' '.join(['{},{}']*3).format(*minmaxes(triplets))) # 1,7 4,6 3,9 
+0

Esta es una mala solución ya que la clasificación es 'O (n × log (n))' mientras que encontrar el mínimo es 'O (n)' – Grief

+0

@Dergonzalez: Parafraseando un idioma popular estadounidense, la generalidad no es libre. – martineau

+0

@cobbal respuesta mejorada por @tiwo no es menos general, pero mucho más sencillo: 'list (map (max, * [(1,9), (2,8), (3,7)]))' returns '[ 3, 9] 'así como 'min'-versión devolvería' [1, 7] ' – Grief

3

Al menos con Python 2.7, el "zip" no es necesario, por lo que se simplifica a map(max, *data) (donde data es un iterador sobre tuplas o listas de la misma longitud).

+0

No estoy seguro de lo que quiere decir, porque' map (max, * alist) 'es' [7, 6] '(como 'map (max, * iter (alist))'). – martineau

+0

@martineau 'map (max, * alist)' devuelve '[7, 5]', al igual que 'map (max, zip (* alist))'. – flornquake

+0

@flornquake: En realidad, ambos dan como resultado '[7, 6]' en Python 2.7. Mi comentario inicial fue porque no hay nada en la pregunta original sobre el uso de 'zip', por lo que no entiendo la relevancia de esta" respuesta ".Tal vez fue un comentario sobre la respuesta de @ cobbal. Sin embargo, no se aplica a la mía que usa 'map (ordenado, zip (* alist))'. – martineau

0

Otra solución usando enumerar y comprensión de lista

alist = [(1,3),(2,5),(2,4),(7,5)] 

for num, k in enumerate(['X', 'Y']): 
    print 'max_%s' %k, max([i[num] for i in alist]) 
    print 'min_%s' %k, min([i[num] for i in alist]) 
Cuestiones relacionadas