2010-02-08 15 views
6

¿Existe una forma fácil (es decir, sin hacer rodar la propia función de clasificación) de ordenar las listas paralelas sin copiar innecesariamente en Python? Por ejemplo:Python ordenar matrices paralelas en su lugar?

foo = range(5) 
bar = range(5, 0, -1) 
parallelSort(bar, foo) 
print foo # [4,3,2,1,0] 
print bar # [1,2,3,4,5] 

he visto los ejemplos usando zip pero parece tonto para copiar todos los datos de las listas paralelas a una lista de tuplas y de vuelta otra vez si esto puede evitarse fácilmente.

+1

¿Qué crees que haría esta parallelSort? Por sus comentarios, parece que ordena foo en orden decreciente y la barra en orden creciente, ¿es así? –

+0

@Paul: Clasifica la barra y manipula foo en bloqueado. – dsimcha

+0

¿Qué dará 'parallelSort' si inicialmente' foo' es '[2,4,6,10,8]' y 'bar' es' [3,7,9,5,1] '? – kennytm

Respuesta

0

Para lograr esto, debe implementar su propio tipo.

Sin embargo: ¿La copia innecesaria duele realmente su aplicación? A menudo, algunas partes de Python también me parecen ineficientes, pero son lo suficientemente eficientes para lo que necesito.

+0

Veo su punto de evitar una optimización prematura, pero algunas veces (siendo este un caso) me gusta escribir código genérico y saber que si alguna vez lo uso en un gran conjunto de datos o algo así "simplemente funcionará". En este caso, estoy más preocupado por quedarse sin memoria que por la velocidad. – dsimcha

+0

y no * su propio tipo * implica el uso de 'zip',' dict', etc.? – SilentGhost

+0

No. Supongamos que implementa su propio quicksort; puede asegurarse de realizar cualquier canje en ambas listas. – bayer

3

¿Hay alguna manera fácil? Sí. Use zip.

¿Existe una "manera fácil de no usar una variante de zip"? No.

Si quisieras explicarte por qué objeta usar zip, sería útil. O bien está copiando objetos, en cuyo caso Python copiará por referencia, o está copiando algo tan liviano en una tupla liviana como para no ser digno de optimización. Si realmente no le importa la velocidad de ejecución pero le preocupa especialmente la presión de la memoria, puede pasar su propio tipo de burbuja (o el algoritmo de su preferencia) a la lista de claves que intercambia la lista de teclas y el objetivo enumera elementos cuando realiza un intercambio. Yo llamaría a esto lo contrario de fácil, pero ciertamente limitaría su conjunto de trabajo.

+3

El hecho de que no se puede pensar de una manera fácil que no use zip no significa que no haya uno - ver mi respuesta . :) –

+0

Tu respuesta está comprimida por otro nombre, así que me paro detrás de "no hay una manera fácil que no use una variante de zip". Sin embargo, esta fue una pregunta tonta, así que, si clasificamos en memoria, lo que son esencialmente tuplas de (sort_value, index) es preferible a ordenar tuplas de (sort_value, target_value), fine. –

+0

"Comprimir con otro nombre"? Ciertamente no, no tiene nada que ver con el ajuste y no modifica los elementos originales en absoluto. De hecho, ni siquiera toca la segunda matriz. –

0

Cualquier solución que puedo imaginar por debajo de la introducción de una especie a partir de cero utiliza índices o un diccionario, o alguna otra cosa que en realidad no es apto para ahorrar memoria. En cualquier caso, usar zip solo aumentará el uso de la memoria por un factor constante, por lo que vale la pena asegurarse de que esto es realmente un problema antes de una solución.

Si llega a ser un problema, puede haber soluciones más efectivas. Dado que los elementos de foo y bar están tan estrechamente relacionados, ¿está seguro de que su representación correcta no es una lista de tuplas? ¿Estás seguro de que no deberían estar en una estructura de datos más compacta si te estás quedando sin memoria, como una matriz numpy o una base de datos (la última de las cuales es realmente buena para este tipo de manipulación)?

(también, por cierto, itertools.izip se puede ahorrar un poco de memoria sobre zip, aunque aún así terminar con la lista cremallera completa en forma de lista como resultado de la ordenada.)

6

Aquí está una manera fácil:

perm = sorted(xrange(len(foo)), key=lambda x:foo[x]) 

Esto genera una lista de permutaciones - el valor en perm [i] es el índice del valor i-ésimo más pequeño de foo. A continuación, puede acceder a ambas listas en orden:

for p in perm: 
    print "%s: %s" % (foo[p], bar[p]) 

Se necesitaría establecer criterios de referencia para saber si es más eficiente, sin embargo - Dudo que hace mucha diferencia.

+0

Cambia 'range' a' xrange' si quieres hacer una diferencia. A menos que esté usando Python 3. –

+0

Hm, cierto. O use .sort en lugar de ordenado, pero eso arruina el one-liner-ness. ;) –

+0

resulta que esto no es mejor que ordenarlos fuera de lugar, porque 'ordenados' va a asignar con avidez mucha memoria, p. 'ordenado (rango (10 ** 6), clave = lambda x: x)'. (Por rango quiero decir xrange, ha sido cambiado en python3) Notarás que una gran parte de tu RAM desaparecerá cuando hagas esto. Resulta que 'sorted' es lo suficientemente inteligente como para no ordenar' range' sin embargo, ten cuidado con las pruebas sin una función 'key ='. – ninjagecko

Cuestiones relacionadas