Sorted in Python : A tutorial

posted on by wael

Data can come from a variety of sources  and it can be stored in various manners. Like for example , we can store data in a list ,in  a dictionary ,or in a string . The question hence is how to sort  data , when one needs to do so ?

In python , instead of creating our  own sorting algorithm , or our own sorting function , we can use the sorted function  , which has a worst case performance –  of O(n log n ).

sorted(iterable,key=None,reverse=False)

The syntax : sorted(iterable,*, key=None, reverse=False)

			
sorted(iterable, * ,  key=None, reverse=False)
					
The sorted function takes an :
  • iterable  : If an object is passed to the iter function , and returns an iterator , it is an iterable .
  • *  : is not part of the arguments ,  it is used to specify that the arguments after it must be named arguments .
  • key :  optional named argument . The function that we want to sort by .
  • reverse : optional  named argument . Used if we want to sort the iterable in reverse order .
The sorted function will return a list containing the sorted elements of the iterable. it doesn’t change the original iterable . sorted does not change the relative order of elements that are equal .

The iterable

Is the iterable that we want to sort . An iterable is an object that if passed to the iter function will return an iterator . An iterator is used to loop over the iterable object , for example by using a for loop.

			
>>> a_list = []
# a list is an iterable
>>> iter(a_list)
# returns an iterator
# output
<list_iterator object at 0x107eb6050>


>>> a_number = 1
# a_number is not an iterable
>>> iter(a_number)
# raise a typeError of object not iterable
# output
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
				

These are some examples of using sorted with an iterable .

>>> list_Original = [5, 2, 6, 2, 1, 7]
>>> sorted_List = sorted(list_Original)
# sorted will return a new sorted list.
>>> sorted_List
[1, 2, 2, 5, 6, 7]
# ###  sorting a list of integers ### 


>>> tuple_Original = ('a', 'o', 'r', 'w', 'f', 'g', 'a', 'b', '')
>>> sorted_Tuple = sorted(tuple_Original)
>>> sorted_Tuple 
['', 'a', 'a', 'b', 'f', 'g', 'o', 'r', 'w']
# ### sorting tuples ### 


>>> set_Orginal = {'e', 'r', 'a', 'o'}
>>> sorted_Set = sorted(set_Orginal)
>>> sorted_Set
['a', 'e', 'o', 'r']
# ### sorting sets ### 


>>> string_Original = 'ifoqqnvakdpu'
>>> sorted_String = sorted(string_original)
>>> sorted_String
['a', 'd', 'f', 'i', 'k', 'n', 'o', 'p', 'q', 'q', 'u', 'v']
# ### sorting string ###



>>> dict_Original = {'r': 4, 'o': 2, 'a': 1, 'b': 8}
>>> sorted_dict_Original_keys = sorted(dict_Original)
>>> sorted_dict_Original_keys
['a', 'b', 'o', 'r']
# Sorting the keys

>>> sorted_dict_Original_keys = sorted(dict_Original.keys()) 
>>> sorted_dict_Original_keys
['a', 'b', 'o', 'r']
# Sorting the keys

>>> sorted_dict_Original_values = sorted(dict_Original.values())
>>> sorted_dict_Original_values
[1, 2, 4, 8]
# Sorting the values


>>> sorted_dict_Original_items = sorted(dict_Original.items())
>>> sorted_dict_Original_items
# dict_Original.items() , is a list 
# containing tuples : 
# [('r', 4), ('o', 2), ('a', 1), ('b', 8)]
# sorted uses the first element of each
# tuple to sort the list . 
[('a', 1), ('b', 8), ('o', 2), ('r', 4)]


# ### sorting dictionaries ###					
					

The key

The key is a function that will do some processing on each item inside this iterable , and return it . By default the key is None , hence no processing is performed on the items of this iterable .

Example One : Comparing  numerical strings as numbers

Let us say we have a list containing some numbers , which are stored as strings , and not as integers . We want the sorting to be performed on the numerical value of the integers and not on their string value . We can use the key parameter , to pass a lambda function or a function which will transform the items inside this list from string to an int .

			
>>> list_of_integer_strings = ['1', '12', '2', '22', '3']

>>> sorted(list_of_integer_strings)
# sorted will compare the  list items
# as strings and not as integer types 
# output
['1', '12', '2', '22', '3']
# '1' < '12' < '2' < '22' < '2'
# ### sorting using  the integers string value  ###


>>> sorted(list_of_integer_strings, key=lambda item: int(item))
# we define the lambda function by Using the lambda keyword .
# Item are the parameters that the lambda function will receive ,
# hence they are the strings in the list '1' '12' ..
# int(item) is the value that the lambda function will return .
# int(item) will convert each integer string to an int .
# sorted will sort the returned values .
# output
['1', '2', '3', '12', '22']
# 1 < 2 < 3 < 12 < 22
# ### sorting by using a lambda function ###


def toInt(str):
    ''' return int(str)'''
    return int(str)

>>> sorted(list_of_integer_strings, key= toInt)
# pass the toInt function to sorted as a key.
# sorted will call it for each item in the 
# list .
# toInt will convert each integer string , to 
# an int . 
# sorted will sort the list based on the int 
# values . 
['1', '2', '3', '12', '22']
# 1 < 2 < 3 < 12 < 22

# ### sorting by using a function ###
                        

Example Two : Sorting by an object attribute

We have the noteBook class . A notebook , has papers , and a price. Hence the noteBook class has two attributes , the number_Of_Papers and the price.

			
class NoteBook:
    def __init__(self, number_Of_Papers, price):
        self.number_Of_Papers = number_Of_Papers
        self.price = price
    def __repr__(self):
        return f'{self.number_Of_Papers} : {self.price}'
# The NoteBook class


note_Books_List = [
    NoteBook(200, 3),
    NoteBook(100, 1.5),
    NoteBook(300, 2),
]  
>>> note_Books_List
[200 : 3, 100 : 1.5, 300 : 2]
# creating some notebooks


>>> sorted( note_Books_List, key=lambda note_Book: note_Book.number_Of_Papers) 
# the lambda function will receive a notebook
# and it will return its number of papers.
# sorted will sort the notebooks by their number 
# of papers.
# output
[100 : 1.5, 200 : 3, 300 : 2]
# sorting by the notebooks number of papers


>>> sorted( note_Books_List, key=lambda note_Book: note_Book.price)  
# the lambda function will return the price 
# for each notebook. sorted will use the price
# to sort the notebooks .
[100 : 1.5, 300 : 2, 200 : 3]
# sorting by the notebooks price
                        

The reverse

By default sorting is performed in ascending order , so from the smallest to the largest . if we want to reverse the sorting , so from the largest to the smallest , we must set the reverse argument to true .

			
>>> a_set = {1, 2, 3, 4, 5}
>>> sorted(a_set, reverse=True)
[5, 4, 3, 2, 1]
					

Using sorted with Different Data Types

We can use sorted with an iterable that contains different data types , as long as these data types implement the __le__ method , and are comparable between one another . If not , then a TypeError is raised .

			
>>> sorted(['a', 1, 'b', 2, 'c', 3])
# int and str are not comparable 
# between one another .
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'int' and 'str'


>>> sorted([2.0, 1, 3.2, 2, 5.1, 3 , 3.0])
# int and float are comparable 
# between one another
# the relative order of 3 and 3.0 is kept
[1, 2.0, 2, 3, 3.0, 3.2, 5.1]