Pregunta ¿Es posible ordenar dos listas (que se refieran entre sí) de la misma manera?


De acuerdo, esta puede no ser la idea más inteligente, pero estaba un poco curioso si esto es posible. Digamos que tengo dos listas:

list1 = [3,2,4,1, 1]
list2 = [three, two, four, one, one2]

Si corro list1.sort(), lo ordenará [1,1,2,3,4] pero ¿hay alguna manera de mantener lista a la lista2 también (así que puedo decir que el elemento 4 pertenece a 'tres')? Mi problema es que tengo un programa bastante complejo que funciona bien con las listas, pero en cierto modo necesito comenzar a hacer referencia a algunos datos. Sé que esta es una situación perfecta para los diccionarios, pero trato de evitar los diccionarios en mi procesamiento porque necesito ordenar los valores clave (si debo usar diccionarios, sé cómo usarlos).

Básicamente, la naturaleza de este programa es que los datos vienen en un orden aleatorio (como el anterior), necesito ordenarlo, procesarlo y luego enviar los resultados (el orden no importa, pero los usuarios necesitan saber qué resultado pertenece a llave). Pensé en ponerlo primero en un diccionario, luego ordenar la lista uno, pero no tendría forma de diferenciar los elementos en el con el mismo valor si no se mantiene el orden (puede tener un impacto al comunicar los resultados a los usuarios). Entonces, idealmente, una vez que obtenga las listas, preferiría encontrar una manera de ordenar ambas listas. es posible?


73
2018-03-19 02:35


origen


Respuestas:


Un enfoque clásico para este problema es utilizar el modismo "decorar, ordenar, decodificar", que es especialmente simple usando el built-in de Python zip función:

>>> list1 = [3,2,4,1, 1]
>>> list2 = ['three', 'two', 'four', 'one', 'one2']
>>> list1, list2 = zip(*sorted(zip(list1, list2)))
>>> list1
(1, 1, 2, 3, 4)
>>> list2 
('one', 'one2', 'two', 'three', 'four')

Estos, por supuesto, ya no son listas, pero eso se remedia fácilmente, si es importante:

>>> list1, list2 = (list(t) for t in zip(*sorted(zip(list1, list2))))
>>> list1
[1, 1, 2, 3, 4]
>>> list2
['one', 'one2', 'two', 'three', 'four']

Vale la pena señalar que lo anterior puede sacrificar velocidad por concisión; la versión in situ, que ocupa 3 líneas, es un poco más rápida en mi máquina para listas pequeñas:

>>> %timeit zip(*sorted(zip(list1, list2)))
100000 loops, best of 3: 3.3 us per loop
>>> %timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100000 loops, best of 3: 2.84 us per loop

Por otro lado, para listas más grandes, la versión de una línea podría ser más rápida:

>>> %timeit zip(*sorted(zip(list1, list2)))
100 loops, best of 3: 8.09 ms per loop
>>> %timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100 loops, best of 3: 8.51 ms per loop

Como señala Quantum7, Sugerencia de JSF es un poco más rápido, pero probablemente solo sea un poco más rápido, porque Python usa el mismo idioma DSU internamente para todos los géneros basados ​​en claves. Simplemente está pasando un poco más cerca del metal desnudo. (Esto muestra qué tan bien optimizado zip las rutinas son!)

Pienso que el zipbasado en el enfoque es más flexible y es un poco más legible, por lo que lo prefiero.


140
2018-03-19 02:45



Puede ordenar índices usando valores como claves:

indexes = range(len(list1))
indexes.sort(key=list1.__getitem__)

Para obtener listas ordenadas de índices ordenados:

sorted_list1 = map(list1.__getitem__, indexes)
sorted_list2 = map(list2.__getitem__, indexes)

En tu caso, no deberías tener list1, list2 sino una sola lista de pares:

data = [(3, 'three'), (2, 'two'), (4, 'four'), (1, 'one'), (1, 'one2')]

Es fácil de crear; es fácil de clasificar en Python:

data.sort() # sort using a pair as a key

Ordenar por el primer valor solamente:

data.sort(key=lambda pair: pair[0])

19
2018-03-19 02:48



Transformada de Schwartz. La clasificación de Python incorporada es estable, por lo que los dos 1s no causa un problema

>>> l1 = [3, 2, 4, 1, 1]
>>> l2 = ['three', 'two', 'four', 'one', 'second one']
>>> zip(*sorted(zip(l1, l2)))
[(1, 1, 2, 3, 4), ('one', 'second one', 'two', 'three', 'four')]

10
2018-03-19 02:44



He usado la respuesta dada por senderle por un largo tiempo hasta que descubrí np.argsort. Así es como funciona.

# idx works on np.array and not lists.
list1 = np.array([3,2,4,1])
list2 = np.array(["three","two","four","one"])
idx   = np.argsort(list1)

list1 = np.array(list1)[idx]
list2 = np.array(list2)[idx]

Encuentro que esta solución es más intuitiva y funciona muy bien. El rendimiento

def sorting(l1, l2):
    # l1 and l2 has to be numpy arrays
    idx = np.argsort(l1)
    return l1[idx], l2[idx]

# list1 and list2 are np.arrays here...
%timeit sorting(list1, list2)
100000 loops, best of 3: 3.53 us per loop

# This works best when the lists are NOT np.array
%timeit zip(*sorted(zip(list1, list2)))
100000 loops, best of 3: 2.41 us per loop

# 0.01us better for np.array (I think this is negligible)
%timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100000 loops, best for 3 loops: 1.96 us per loop

Aunque np.argsort no es el más rápido, me resulta más fácil de usar.


8
2017-10-09 23:04



Qué pasa:

list1 = [3,2,4,1, 1]
list2 = ['three', 'two', 'four', 'one', 'one2']

sortedRes = sorted(zip(list1, list2), key=lambda x: x[0]) # use 0 or 1 depending on what you want to sort
>>> [(1, 'one'), (1, 'one2'), (2, 'two'), (3, 'three'), (4, 'four')]

3
2018-03-19 02:46



Una forma es rastrear a dónde va cada índice clasificando la identidad [0,1,2, .. n]

Esto funciona para cualquier cantidad de listas.

Luego mueve cada elemento a su posición. Usar empalmes es lo mejor.

list1 = [3,2,4,1, 1]
list2 = ['three', 'two', 'four', 'one', 'one2']

index = range(len(list1))
print index
'[0, 1, 2, 3, 4]'

index.sort(key = list1.__getitem__)
print index
'[3, 4, 1, 0, 2]'

list1[:] = [list1[i] for i in index]
list2[:] = [list2[i] for i in index]

print list1
print list2
'[1, 1, 2, 3, 4]'
"['one', 'one2', 'two', 'three', 'four']"

Tenga en cuenta que podríamos haber iterado las listas sin siquiera ordenarlas:

list1_iter = (list1[i] for i in index)

2
2018-03-19 02:52



Puedes usar el zip() y sort() funciones para lograr esto:

Python 2.6.5 (r265:79063, Jun 12 2010, 17:07:01)
[GCC 4.3.4 20090804 (release) 1] on cygwin
>>> list1 = [3,2,4,1,1]
>>> list2 = ['three', 'two', 'four', 'one', 'one2']
>>> zipped = zip(list1, list2)
>>> zipped.sort()
>>> slist1 = [i for (i, s) in zipped]
>>> slist1
[1, 1, 2, 3, 4]
>>> slist2 = [s for (i, s) in zipped]
>>> slist2
['one', 'one2', 'two', 'three', 'four']

Espero que esto ayude


1
2018-03-19 02:44



Puede usar el argumento clave en el método ordenado () a menos que tenga dos valores iguales en list2.

El código se da a continuación:

sorted(list2, key = lambda x: list1[list2.index(x)]) 

Clasifica list2 de acuerdo con los valores correspondientes en list1, pero asegúrese de que al usar esto, no hay dos valores en list2 que se evalúen como iguales porque la función list.index () proporciona el primer valor


0
2018-05-16 08:51