user3808269
user3808269

Reputation: 1351

Confused by sorted(..., key=lambda...)

Could someone please explain these lambdas? I am fairly confused by the following code and would appreciate some help understanding the code from someone who knows about this and can break the code down into understandable components.

convert = lambda text: int(text) if text.isdigit() else text
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
return sorted(l, key = alphanum_key)

(source: https://arcpy.wordpress.com/2012/05/11/sorting-alphanumeric-strings-in-python/)

I understand the first lambda.

For the second lambda alphanum_key I am confused. It seems that a key is passed in to the lambda and used in the split() function in the re module, but I do not see a key passed into the alphanum_key lambda when this lambda is called in the sorted() function.

I wrote a small program to see if I could create normal def functions out of the lambdas that are apparently using bad form by returning values and being called like functions. Here is my code:

import re

def convert2(text):
    if text.isdigit():
        return int(text)
    else:
        return text

def alphanum_key2(key):
    a_list = []
    for i in re.split('([0-9]+)', key):
        a_list.append(convert2(i))

    return a_list


if __name__ == "__main__":
    things = ["10bags", "500miles", "10000maniacs", "2000lightYearsFromHome"]
    x = sorted(things, key= alphanum_key2)
    print(x)
    #This prints
    #['10bags', '500miles', '2000lightYearsFromHome', '10000maniacs']

    convert = lambda text: int(text) if text.isdigit() else text
    alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
    print(sorted(things, key = alphanum_key))
    #This prints
    #['10bags', '500miles', '2000lightYearsFromHome', '10000maniacs']

This leads to a second question... Why is the normal def functions that mimic the lambda functions returning different and incorrect results. Please note the results returned in the comments of the code if you do not feel like running this program on your machine.

Upvotes: 2

Views: 272

Answers (1)

Mark Ransom
Mark Ransom

Reputation: 308140

You say you understand the first function convert so I won't go into that; just be aware that it returns either a string or an integer.

The straightforward conversion of the second from a lambda is:

def alphanum_key(key):
    return [convert(c) for c in re.split('([0-9]+)', key)]

Let's break that down.

[... for ...]

That's a list comprehension. It will create a list containing an element for each iteration of the for.

re.split('([0-9]+)', key)

This uses a regular expression consisting of all the digits ([0-9]) repeated one or more times (+). By putting parentheses around this expression those matches will be included in the output from split.

>>> re.split('([0-9]+)', "10bags")
['', '10', 'bags']

There's an empty string at the beginning since split splits apart the string at the matches and returns the parts both before and after the match.

The final output of alphanum_key will be ['', 10, 'bags'] since '10' will be converted to the integer 10. This is important because you want to compare numbers:

>>> '10000' < '500'
True
>>> 10000 < 500
False

Upvotes: 1

Related Questions