listas: usort para el enésimo elemento en tupla
Pregunta
Necesito ordenar las tuplas de acuerdo con el segundo elemento de cada tupla, pero aparentemente usort / 1 solo funciona con el primer elemento. Así que tengo que intercambiar los elementos, ordenarlos y volver a cambiar. ¿Hay alguna manera más fácil? También hay una forma de ordenar en orden descendente (sé que se puede ordenar e invertir, pero solo quiero saber).
Solución
¿Has probado la función keysort / 2 (o su contraparte ukeysort / 2 )?
> lists:reverse(lists:keysort(2, [{a,2}, {b,1}, {c, 3}])).
[{c,3},{a,2},{b,1}]
Si no ordena listas muy grandes, esta es probablemente la solución más legible que puede obtener.
Otros consejos
En realidad, una mejor respuesta:
Hay una segunda versión de sort que toma una función de clasificación:
lists:sort(Fun, List1) -> List2
Aquí hay un ejemplo que se ordena en el segundo elemento de una tupla:
lists:sort(fun(A, B) ->
{A1, A2} = A,
{B1, B2} = B,
if
A2 > B2 ->
false;
true ->
true
end
end, YourList).
Una versión mejorada de la solución de bmdhacks:
lists:sort(fun(A, B) ->
{_, A2} = A,
{_, B2} = B,
A2 =< B2
end, YourList).
Los guiones bajos son mejores que A1 y B1, porque el compilador dará advertencias para aquellos.
Para ordenar en orden descendente, simplemente cambie < = a > =.
No debería ser demasiado difícil escribir su propia función de clasificación (adaptada de un ejemplo común):
qsort([]) -> [];
qsort([Pivot|Tail]) ->
{PivotFirst, PivotSecond} = Pivot,
qsort([{FirstElement, SecondElement} || {FirstElement,SecondElement} <- Tail, SecondElement < PivotSecond])
++ [Pivot] ++
qsort([{FirstElement, SecondElement} || {FirstElement,SecondElement} <- Tail, SecondElement >= PivotSecond]).