Sort a list of tuples by value and then alphabetically
Solution 1
You can use the sorted
function:
sorted_by_medals = sorted(list_of_medals, key=lambda tup: (-tup[1], tup[0]))
Solution 2
In this instance, I'd use a lambda function as the key
argument to sort()
/sorted()
:
In [59]: sorted(list_of_medals, key=lambda x:(-x[1],x[0]))
Out[59]:
[('Sweden', 24),
('Germany', 16),
('Ireland', 10),
('Russia', 10),
('Spain', 9),
('Albania', 8),
('Lithuania', 7),
('Iceland', 6),
('Italy', 5),
('Malta', 5),
('Estonia', 4),
('Serbia', 4),
('Turkey', 4),
('Azerbaijan', 2),
('Moldova', 2)]
The negation of x[1]
is needed to sort the medals in descending order while sorting country names in ascending order (simply setting reverse=True
wouldn't achieve that).
As several people have pointed out in the comments, a more general way to do a complex sort on a compound key is to perform several sorting steps. To do this, sort on one component at a time, starting with the least significant one:
In [67]: temp = sorted(list_of_medals, key=itemgetter(0))
In [68]: sorted(temp, key=itemgetter(1), reverse=True)
Out[68]:
[('Sweden', 24),
('Germany', 16),
('Ireland', 10),
('Russia', 10),
...
This relies on the fact that Python's sort is stable, meaning that items that compare equal are never reordered.
user1830011
Updated on June 09, 2022Comments
-
user1830011 almost 2 years
Bit of a python newbie, but I got the following list of tuples. I need to sort it by value and if the value is the same, solve ties alphabetically. Here's a sample:
#original list_of_medals = [('Sweden', 24), ('Germany', 16), ('Russia', 10), ('Ireland', 10), ('Spain', 9), ('Albania', 8), ('Lithuania', 7), ('Iceland', 6), ('Malta', 5), ('Italy', 5), ('Serbia', 4), ('Estonia', 4), ('Turkey', 4), ('Moldova', 2), ('Azerbaijan', 2)] # \____/ \_____/ \______/ #after sorting / \ / \ / \ sorted_medals = [('Sweden', 24), ('Germany', 16), ('Ireland', 10), ('Russia', 10), ('Spain', 9), ('Albania', 8), ('Lithuania', 7), ('Iceland', 6), ('Malta', 5), ('Italy', 5), ('Estonia', 4), ('Serbia', 4), ('Turkey', 4), ('Azerbaijan', 2), ('Moldova', 2)]
Is it perhaps possible with the
operator
module? -
NPE over 11 yearsThis ignores the country name and thus doesn't meet the spec.
-
bmu over 11 yearsthis doesn't sort alphabetically if the values are the same
-
Steven Rumbalski over 11 yearsMissed requirement: "if the value is the same, sorted alphabetically."
-
mgilson over 11 yearsI think that it is also worth mentioning the fact that python's sort is "stable". While you don't need it in this case because you can easily sort big->small just by
-x[1]
, with other types it isn't quite so easy and you may be forced to do the sorting in 2 steps. -
Katriel over 11 yearsYou could also sort twice, because Python sort is stable.
-
mgilson over 11 yearsWon't this now sort reversed alphabetically if the numbers are the same?
-
jfs over 11 years@mgilson: could you provide an example where you can't use
key
function and have to use 2-step sort? -
NPE over 11 years@J.F.Sebastian: Let's say instead of the numeric medal count we had a string that had to be sorted lexicographically in descending order. The negation trick wouldn't work, and the two sorts would probably be the cleanest way to do the compound ascending/descending sort.
-
mgilson over 11 years@NPE -- Thanks, that was the exact example I was going to give.
-
jfs over 11 years@mgilson: notice that I've used "can't" and "have to". "forced to" is not the synonym for "the cleanest". Custom
cmp
function withcmp_to_key
can handle it e.g.,lambda x,y: cmp(y[1], x[1]) or cmp(x[0], y[0])
. -
mgilson over 11 years@J.F.Sebastian -- Ok, that's fair. Given a situation, you probably could come up with something that would work, but as you say, it's definitely not the cleanest.