# Sort examples
# 1. Basic sort
# The in-built function sorted()
# does not change the original list and returns
# its sorted copy
print( 'function sorted():' )
L1 = [6, -2, 5, 0, 12, 5]
sortedL1 = sorted( L1 )
print( L1 ); print( sortedL1 )
print()
# The function sort() is a method of any list,
# it sorts the list nad changes the order of items in it.
print( 'method sort():' )
L1 = [6, -2, 5, 0, 12, 5]
print( L1 )
L1.sort()
print( L1 );
print()
# Sorting in reverse non-increasing (non-ascending) order
# can be done in both sort() and sorted() by specifying
# the reverse parameter:
print( 'reverse sorting by sort() and sorted():' )
L1 = [6, -2, 5, 0, 12, 5]
sortedL1 = sorted( L1, reverse = True )
print( L1 ); print( sortedL1 )
L1 = [6, -2, 5, 0, 12, 5]
print( L1 )
L1.sort( reverse = True )
print( L1 );
print()
# 2. Sorting more structured items
# Example:
# List of items, each item is a list of values
# Sorting methods needs a specification,
# what information/value related to an item in the array
# is a key to its position in the sorted array.
# The array is then sorted in the order of that key information.
print( 'sorting by the second component in each item :' )
L1 = [ [1,2,3], [4,0,4,5], [1,7], [5,1,2], [9,0,0] ]
print( L1 )
sortedL1 = sorted( L1, key = lambda x: x[1] )
# lambda takes the parameter which immediately follows it
# and transforms it to the expression after the colon.
# Thus, any item x that is being sorted, is sorted according
# to its second component.
# Keyword 'key' is followed by the equality sign and then by
# specification of the property by which the items are sorted.
# The property is defined by a function, typically supplied by the programmer.
print( sortedL1 )
print()
print( 'sorting by the sum of components of each item :' )
L1 = [ [1,2,3], [4,0,4,5], [1,7], [5,1,2], [9,0,0] ]
print( L1 )
# note the change in the lambda function
sortedL1 = sorted( L1, key = lambda x: sum( x ) )
print( sortedL1 )
print( 'To verify visually:' )
print( [ (item, sum(item)) for item in sortedL1 ] )
print()
# 3. Sorting using more criteria simultaneously
# with the help of comparator function
# We are given a list of strings.
# The sort criteria in the descending order of importance are:
# 1. Number of characters 'a' in the string ( more 'a's is more important )
# 2. Length of the string ( shorter is more important )
# 3. First character of the string ( respect alphabet order )
#
# We have to provide a comparator -- function which takes two strings and
# returns a value indicating the relation between the strings -
# -1 first string is smaller than the second one
# 0 strings are equal
# 1 first string is bigger than the second one
def ourComparator( str1, str2 ):
# 1. criterion - Number of characters 'a' in the string
a_count1 = str1.count( "a" )
a_count2 = str2.count( "a" )
if a_count1 > a_count2: return -1 # str1 is smaller = more important
if a_count1 < a_count2: return 1 # str1 is bigger = less important
# now, the number of a's in both strings is the same
# when items are equal in the 1st criterion, consider the 2nd criterion:
if len(str1) < len(str2): return -1 # str1 is smaller = more important
if len(str1) > len(str2): return 1 # str1 is bigger = less important
# now, the strings are equal according to both 1st and 2nd criterion:
# consider the third criterion
if str1[0] < str2[0]: return -1 # str1 is smaller = more important
if str1[0] > str2[0]: return 1 # str1 is bigger = less important
# now, strings are considered equal, or better, we do not dinstinguish between them
return 0
import functools
# In Python 3.x, the comparator has to be turned FORMALLY(!) into a key
# like in the example:
# myComparatorKey = functools.cmp_to_key( myComparatorFunction )
# myList.sort( key=myComparatorKey )
ourComparatorKey = functools.cmp_to_key( ourComparator )
print( 'sorting by complex criteria :' )
L1 = [ 'hello', 'zaxa', 'zaaaa', 'zaa', 'baxa', 'f' ]
print( L1 )
sortedL1 = sorted( L1, key = ourComparatorKey )
print( sortedL1 )
print()
# Note on Sorts
# Although there are relatively rare instances
# when a custom built search would be slightly
# faster than a built-in sort method,
# the built-in method is reliably fast and if used with care
# it does not affect seriously the time of the whole code execution.
# When regarding the effectivity of the sort,
# the most simple and crude rule of thumb may be the following:
# Data size < 1000
# sort method passes through the entire data list less than 10 times.
# Data size > 1000
# sort method passes through the entire data list more than 10 times,
# but less than 50 times.
# Example problem: Pairs of values with given sum
# In a given array, find all pairs of values
# which sum equals to a given fixed value.
# Sort the array, consider a pair P
# made of the first and the last item in the sorted array.
# Now, proceed in steps:
# In one step make the following checks
# If the sum of P is too small, substitute the first item in P
# by its neighbour to the right in the sorted array.
# That neighbour value is either the same or bigger.
# If the sum of P is too big, substitute the second item in P
# by its neighbour to the left in the sorted array.
# That neighbour value is either the same or smaller.
# If the sum of P is equal to the given sum value,
# either stop and announce success
# or substitute both values in the pair by their respective
# closest different values to the right and to the left.
# Stop when the first value in the pair
# is bigger or equal to the second value in the pair.
def allValuePairsWithGivenSum( arr, givenSum ):
arrSrt = sorted( arr )
pairs = []
index1, index2 = 0, len(arr)-1
while index1 < index2:
currSum = arrSrt[index1] + arrSrt[index2]
# the two candidates, on index1 and index2,
# are not appropriate
if currSum < givenSum:
index1 += 1 # try to increase the current sum
if currSum > givenSum:
index2 -= 1 # try to decrease the current sum
# now, an apprropriate pair has been found,
# register it and move to a next candidate
if currSum == givenSum:
pairs.append( [arrSrt[index1], arrSrt[index2]] )
# time to stop?
if arrSrt[index1] == arrSrt[index2]:
break
# move to next candidate on the left
currLeftValue = arrSrt[index1]
index1 += 1
while arrSrt[index1] == currLeftValue: index1 += 1
# move to next candidate on the right
currRightValue = arrSrt[index2]
index2 -= 1
while arrSrt[index2] == currLeftValue: index2 -= 1
# end of while
return pairs
a = [ 9, 4, 11, 7, 3, 3, 4, 5, 2, 9, 1, 4, 6 ]
givenSum = 10
w = allValuePairsWithGivenSum( a, givenSum )
print(w)
'''
a = [ [6,10], [7,13], [2, 20], [9, 11] ]
b = [ [6,10], [7,13], [2, 20], [9, 11] ]
z = sorted( a, key=lambda x: x[0] )
b.sort( key=lambda x: x[1] )
print( z )
print( b )
'''