Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass multiple arguments to the method 'key' of sorted()?

On a website, I am trying to sort a list of shop by their relative position of the user. Let me explain.

A shop looks something like this:

class Shop(models.Model):
    latitude = models.DecimalField(max_digits=9, decimal_places=6)
    longitude = models.DecimalField(max_digits=9, decimal_places=6)

I get the position of the user in the session.

request.session['user_latitude']
request.session['user_longitude']

So now I got a list of shop and I want to sort them. So I tried this:

def distance_of_the_shop(shop):
    # compute the distance between the shop and the user and return it
    return computed_distance

sorted(shop_list, key=distance_of_the_shop)

The question is pretty simple, how to pass more than one argument to the method distance_of_the_shop?

like image 362
Thom Avatar asked Mar 18 '14 15:03

Thom


People also ask

How do you pass multiple keyword arguments in Python?

**kwargs: Pass multiple arguments to a function in Python If so, use **kwargs . **kwargs allow you to pass multiple arguments to a function using a dictionary. In the example below, passing **{'a':1, 'b':2} to the function is similar to passing a=1, b=1 to the function.

How do you pass multiple arguments to a function?

The * symbol is used to pass a variable number of arguments to a function. Typically, this syntax is used to avoid the code failing when we don't know how many arguments will be sent to the function.

Does Python allows you to pass multiple arguments to a function?

Every function in Python receives a predefined number of arguments, if declared normally, like this: def myfunction(first, second, third): # do something with the 3 variables ... The "bar" function receives 3 arguments.


2 Answers

Just wrap the call in a lambda:

ulong, ulat = request.session['user_latitude'], request.session['user_longitude']
sorted(shop_list, key=lambda shop: distance_of_the_shop(shop, ulong, ulat))

and add two more arguments to the distance_of_the_shop() function to receive the longitude and latitude.

The sorted() function calls the key for each value in shop_list, but nothing says the callable cannot itself call other functions. A lambda is the easiest way to create a new wrapper function that does just that.

You could also use a functools.partial() object, provided the longitude and latitude values can be passed in as keyword arguments, or accepts those two values as the first two positional arguments. Treating them as keyword arguments is probably best, even if they are given a position (no default value), you can use their names as keyword arguments in the partial().

Assuming the definition is:

def distance_of_the_shop(shop, long, lat):
    # ...

then use

sorted(shop_list, key=partial(distance_of_the_shop, long=ulong, lat=ulat))

and sorted() will pass each shop to the partial(), which in turn calls distance_of_the_shop(shop, long=ulong, lat=ulat)

like image 168
Martijn Pieters Avatar answered Oct 06 '22 01:10

Martijn Pieters


Your question is hard to comprehend because you never define a distance function, and the function you do provide, distance_of_the_shop, actually takes a single argument.

If I understand correctly, you would like distance_of_the_shop to receive the current user and the shop being compared. To achieve that, use a lambda:

shop_list.sort(key=lambda shop: distance_of_the_shop(user, shop))

Also note that it doesn't make sense to call sorted without assigning its value to some variable or container. If you want to sort a list in-place, use its sort method, as shown above.

like image 39
user4815162342 Avatar answered Oct 06 '22 01:10

user4815162342