3

I need to sort the below list :

[('Elijah', 51), ('Chloe', 144), ('Elizabeth', 485), ('Matthew', 485), ('Natalie', 207), ('Jayden', 390)] 

It should be sorted based on the no. And if there are any two similar no's it is sorted alphabetically according to the name. The final ans should be

[('Elizabeth', 485), ('Matthew', 485), ('Jayden', 390), ('Natalie', 207), ('Chloe', 144), ('Elijah', 51)]. 

I am not able to understand the method given by the author. He wrote:

scores.sort(key=lambda x: (-x[1],x[0])) print(scores) 

In this scores refer to the above given list. Can anyone explain me what exactly happens.

2
  • Read this: docs.python.org/3/howto/sorting.html#key-functions Commented Oct 8, 2019 at 9:09
  • 1
    What exactly do you not understand? What key does, what lambda is, what x[1] is, or why the -? Or do you want to know how exactly it works "under the hood"? Commented Oct 8, 2019 at 9:12

2 Answers 2

2

Breakdown:

list.sort:

scores.sort(...) # sorts the list in-place 

This method sorts the list in place, using only < comparisons between items. Exceptions are not suppressed - if any comparison operations fail, the entire sort operation will fail (and the list will likely be left in a partially modified state).

key parameter in sort:

key=... # sort the list by some function applied to each item 

key specifies a function of one argument that is used to extract a comparison key from each list element (for example, key=str.lower). The key corresponding to each item in the list is calculated once and then used for the entire sorting process. The default value of None means that list items are sorted directly without calculating a separate key value.

The key function:

lambda x: (-x[1],x[0]) # sort each item by the second and then first member 

The negation (-x[1]) is only so that the list is sorted in reversed manner relating to the first item (biggest to smallest).

Depending on what the expected output is, using the reversed parameter may have been more clear:

reverse is a boolean value. If set to True, then the list elements are sorted as if each comparison were reversed.

Sign up to request clarification or add additional context in comments.

2 Comments

@CharifDZ its nice when you want to partially reverse the comparison (reverse only the first item, like in this case). It is cryptic so generally I would avoid it.
I didn't read the question carefully up vote the good explanation
1

Itemgetter is a neat tool for sorting like this as it can be used hierarchically. See below...

from operator import itemgetter as ig data_sorted = sorted(data, key=ig(1,0), reverse=True) 

The reverse changes ascending vs. descending.

EDIT:

As was pointed out this will only address sorting one column. The easiest solution would be to sort twice. First by the secondary sorting column (name in this case), and then by the primary sorting column (Number Value).

ds1 = sorted(data, key=ig(0), reverse=True) ds2 = sorted(ds1, key=ig(1), reverse=True) 

Resulting in...

('Elizabeth', 485) ('Matthew', 485) ('Jayden', 390) ('Natalie', 207) ('Chloe', 144) ('Elijah', 51) 

3 Comments

But your solution sorts names descending as well (when elements have the same number) which is not according to spec.
@RoelSchroeven edited to address your concern. Thanks for the feedback.
I like that approach (the one after the edit). Perhaps not the most efficient, but I think it makes sorting on different things with possibly different orders more clear.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.