Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lambda function in sorted dictionary list comprehension

I have the following dictionary:

student_loan_portfolio = {
    'loan1': {'rate': .078, 'balance': 1000, 'payment': 100, 'prepayment': 0},
    'loan2': {'rate': .0645, 'balance': 10, 'payment': 5, 'prepayment': 0},
    'loan3': {'rate': .0871, 'balance': 250, 'payment': 60, 'prepayment': 0},
    'loan4': {'rate': .0842, 'balance': 200, 'payment': 37, 'prepayment': 0},
    'loan5': {'rate': .054, 'balance': 409, 'payment': 49, 'prepayment': 0},
    'loan6': {'rate': .055, 'balance': 350, 'payment': 50, 'prepayment': 0}
}

I would like to iterate through the containing dictionary (with keys loan1 through loan6) in order of the key containing the dictionary with the highest 'rate' value in its respective nested dictionary. That is, I would like to iterate in order of loan3, loan4, loan1, loan2, loan6, loan5

Thanks to @Jame Sharp the easiest way to do this that I know is:

for k,v in sorted(student_loan_portfolio.items(), key=lambda (k,v): v['rate'], reverse=True):

I am now reading about lambda and cannot really understand exactly how and why this works. First, v['rate'] I believe is returning the value of those dictionary keys. But its seems like it should be some kind of syntax error. what is v['rate'] referencing and what is the logic behind the syntax?

On a related note, why, do we have to specify the inputs to the lambda function as a tuple?

And how are the following cases different?

#1

>>>f = lambda x,y,z:x + y + z
>>>f(1,2,3)

#6

>>>f = lambda (x,y,z): x + y + z
>>>f(1,2,3)

Traceback (most recent call last):
  File "<pyshell#48>", line 1, in <module>
    f(1,2,3)
TypeError: <lambda>() takes exactly 1 argument (3 given)

Thank you for the clarification.

like image 788
cdelsola Avatar asked Dec 08 '12 21:12

cdelsola


2 Answers

lambda (k,v): v['rate'] is a function that takes a single argument (a 2-tuple), and returns the 'rate' key of the second entry in the tuple. It is equivalent to lambda t: t[1]['rate']

lambda x,y,z:x + y + z is a function which takes 3 values and returns their sum.

lambda (x,y,z): x + y + z is a function that takes 1 value (a 3-tuple), and returns the sum of its elements.

like image 65
Eric Avatar answered Sep 21 '22 20:09

Eric


The items() method on student_loan_portfolio.items() returns a list of key/value tuples. So it returns something like [ ('loan1', dictOfLoan1), ('loan2', dictOfLoan2), ...]. The lambda accepts this tuple as an argument, and reads the "rate" item from the value dict (i.e., it reads dictOfLoan1['rate'], dictOfLoan2['rate'], etc.).

You could achieve the same effect by using, instead of the lambda you have, lambda item: item[1]['rate']. item is a tuple (key, value), so item[1] is the value.

The difference between your two lambda examples is that the first one accepts three arguments, while the second accepts a single argument which is a three-element tuple. The ability to define a function which accepts tuples as arguments but unpacks their contents into separate local variables was a quirk of Python that was removed in Python 3 (see PEP 3113).

like image 39
BrenBarn Avatar answered Sep 21 '22 20:09

BrenBarn