I wish to sort the below list first by the number, then by the text.
lst = ['b-3', 'a-2', 'c-4', 'd-2']
# result:
# ['a-2', 'd-2', 'b-3', 'c-4']
Attempt 1
res = sorted(lst, key=lambda x: (int(x.split('-')[1]), x.split('-')[0]))
I was not happy with this since it required splitting a string twice, to extract the relevant components.
Attempt 2
I came up with the below solution. But I am hoping there is a more succinct solution via Pythonic lambda
statements.
def sorter_func(x):
text, num = x.split('-')
return int(num), text
res = sorted(lst, key=sorter_func)
I looked at Understanding nested lambda function behaviour in python but couldn't adapt this solution directly. Is there a more succinct way to rewrite the above code?
The list. sort() method key parameter is set to lambda. The arguement x is the iterable element ( tuple ) to be sorted by the second element, the number. The lambda expression sorts the list by the second element of the tuple value and updates the original.
A lambda function inside a lambda function is called a nested lambda function. Python allows lambda nesting, i.e., you can create another lambda function inside a pre-existing lambda function. For nesting lambdas, you will need to define two lambda functions – an outer and an inner lambda function.
The use of lambda creates an anonymous function (which is callable). In the case of sorted the callable only takes one parameters. Python's lambda is pretty simple. It can only do and return one thing really. The syntax of lambda is the word lambda followed by the list of parameter names then a single block of code.
Use the list sort() method to sort a list with a lambda expression in Python. Just call the list. sort(key=None) with a key set to a lambda expression to sort the elements of the list by the key. Both list.
There are 2 points to note:
lambda
statement, as function composition is not part of the standard library (see Note #1). What you can do easily is have one lambda
function return the result of another lambda
function.Therefore, the correct answer can found in Lambda inside lambda.
For your specific problem, you can use:
res = sorted(lst, key=lambda x: (lambda y: (int(y[1]), y[0]))(x.split('-')))
Remember that lambda
is just a function. You can call it immediately after defining it, even on the same line.
Note #1: The 3rd party toolz
library does allow composition:
from toolz import compose
res = sorted(lst, key=compose(lambda x: (int(x[1]), x[0]), lambda x: x.split('-')))
Note #2: As @chepner points out, the deficiency of this solution (repeated function calls) is one of the reasons why PEP-572 is considered implemented in Python 3.8.
We can wrap the list returned by split('-')
under another list and then we can use a loop to handle it:
# Using list-comprehension
>>> sorted(lst, key=lambda x: [(int(num), text) for text, num in [x.split('-')]])
['a-2', 'd-2', 'b-3', 'c-4']
# Using next()
>>> sorted(lst, key=lambda x: next((int(num), text) for text, num in [x.split('-')]))
['a-2', 'd-2', 'b-3', 'c-4']
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With