Tengo dos listas, p.

coords = [2, 0, 1, 4, 3]
value = [1, 9, 3, 3, 0]

Donde el primero es una serie de coordenadas, y el segundo es una serie de valores correspondientes a las coordenadas, p. la coordenada '2' corresponde al valor '1', las coordenadas '0' dan el valor '9'.

Ahora, me gustaría ordenar coords pero mantener el orden de value sin cambios, de modo que el elemento más pequeño coords corresponda al elemento más pequeño en {{X3 }}, y así. El resultado deseado sería:

coords_new = [1, 4, 2, 3, 0]
value = [1, 9, 3, 3, 0] # unchanged

Donde '0' -> '0', '1' -> '1', '2' -> '3', '3' -> '3', '4' -> '9'. ¿Alguna idea para hacer eso? Puede devolver coords_new, o los índices que reordenan coords como respuesta.

Editar: Si es posible, prefiero que podamos devolver los índices que reordenan el coords original, es decir, devolver el idx tal que coords[idx] = coords_new.

¡Muchas gracias!

Zhihao

2
Zhihao Cui 14 sep. 2018 a las 22:53

3 respuestas

La mejor respuesta

Aquí hay una solución y media usando argsort. El argumento kind='mergesort' kwd solo es necesario si necesita una ordenación estable. En su ejemplo, una ordenación inestable también puede generar coords_new == [1, 4, 3, 2, 0]. Si eso no es un problema, puede omitir el argumento kwd y permitir que numpy use un algoritmo de ordenación más rápido.

import numpy as np

coords = [2, 0, 1, 4, 3]
value = [1, 9, 3, 3, 0]

coords, value = map(np.asanyarray, (coords, value))

vidx = value.argsort(kind='mergesort') # mergesort is stable, i.e. it  
                                       # preserves the order of equal elements

# direct method:
coords_new = np.empty_like(coords)
coords_new[vidx] = np.sort(coords)

# method yielding idx
idx = np.empty_like(vidx)
idx[vidx] = coords.argsort(kind='mergesort') 

El segundo método produce idx tal que coords_new == coords[idx].

1
Paul Panzer 15 sep. 2018 a las 05:44

Supongo que quieres una respuesta numpy ya que has etiquetado numpy:

>>> x = np.argsort(value)
>>> x[x]
array([1, 4, 2, 3, 0])
0
wim 14 sep. 2018 a las 20:25

Una alternativa es crear primero la asignación entre los objetos y luego usar esta asignación combinada con el índice:

coords = [2, 0, 1, 4, 3]
value = [1, 9, 3, 3, 0]

table = {k: v for k, v in zip(sorted(coords), sorted(value))}
print(table)
print(sorted(coords, key=lambda e: value.index(table[e])))

Salida

{0: 0, 1: 1, 2: 3, 3: 3, 4: 9}
[1, 4, 2, 3, 0]

Nota

Este método supone que coords solo contiene valores únicos. Para el caso general, podría generar los pares (c, v) de la asignación y ordenarlos por el valor de índice de v en valor:

pairs = [(k, v) for k, v in zip(sorted(coords), sorted(value))]
result = [k for k, _ in sorted(pairs, key=lambda e: value.index(e[1]))]

print(result)

Salida

[1, 4, 2, 3, 0]
3
Dani Mesejo 14 sep. 2018 a las 20:12