The problem of using itemgetter
or tuples (as suggested in another answer) is that both elements will be ordered by the same criterion (either both in ascending order, or both in nonexistent order). Even if you use reverse=True
, this will be applied in both.
If the idea is that one is in descending order and the other in ascending order, an alternative is to reverse the signal of one of them:
def comp(item): # primeiro item em ordem decrescente, segundo em ordem crescente
return -item[1], item[0]
listaqq = [(4,2),(5,2),(7,3),(9,4),(6,4)]
sortedLista = sorted(listaqq, key=comp)
print(sortedLista) # [(6, 4), (9, 4), (7, 3), (4, 2), (5, 2)]
Or, using lambda instead of a function:
sortedLista = sorted(listaqq, key=lambda item: (-item[1], item[0]))
In that case you don’t need to use reverse=True
. As I reversed the sign of the second element of the tuple, they will be ordered in descending order. In the case of a tie, the value of the first element will be used (in ascending order).
The result will be the list [(6,4),(9,4),(7,3),(4,2),(5,2)]
.
Already using the another solution that you saw:
def compare(t1, t2):
# compara o segundo elemento de cada tupla, em ordem decrescente
cmp = t2[1] - t1[1]
if cmp == 0: # se forem iguais, compara o primeiro elemento de cada tupla, em ordem crescente
cmp = t1[0] - t2[0]
return cmp
import functools
sortedLista = sorted(listaqq, key = functools.cmp_to_key(compare))
print(sortedLista)
The idea is that the comparison function returns a negative number if the first element is "smaller" (i.e., whether it should come earlier in ordering), 0
if they are equal and a positive number if it is "higher" (if it should come later in ordering).
Then I can simply subtract the second element of the second tuple by the second element of the first: if the result is positive, that is to say that the first tuple must come later in the ordering (that is, the elements are ordered in descending order).
If the result of the subtraction is zero, that means that the second element of tuples are equal, and then I do the tiebreaker for the first element (but now subtracting the element from the first tuple before, so that it is in ascending order).
At last, I use cmp_to_key
so that the comparison function is converted to a key Function and can be used in sorted
.
I don’t think that produces the expected result, because in the case will order by
item[1]
in descending order, and the tiebreaker withitem[0]
will also be in descending order (but the tie break should be in ascending order) - I left an answer with an alternative (but I don’t know if it was too much gambiarra or if it has a more elegant way - feel free to comment there)– hkotsubo
ah - actually just do
lambda item; -item[1], item[0]
and take out the verse.– jsbueno
This - as Victor did there - I used sesse Pattern myself recently - I can’t even remember where.
– jsbueno