如何将多个参数传递给sorted()的方法'key'?

时间:2022-01-23 10:11:50

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?

问题很简单,如何将多个参数传递给distance_of_the_shop方法?

3 个解决方案

#1


10  

Just wrap the call in a lambda:

只需将调用包装在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.

并向distance_of_the_shop()函数添加两个参数以接收经度和纬度。

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.

sorted()函数为shop_list中的每个值调用键,但没有任何内容表示callable本身不能调用其他函数。 lambda是创建新包装函数的最简单方法。

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().

您还可以使用functools.partial()对象,前提是经度和纬度值可以作为关键字参数传递,或者将这两个值作为前两个位置参数接受。将它们作为关键字参数处理可能是最好的,即使给它们一个位置(没有默认值),你也可以在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)

而sorted()会将每个商店传递给partial(),而partial()又调用distance_of_the_shop(shop,long = ulong,lat = ulat)

#2


1  

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.

您的问题很难理解,因为您从未定义距离函数,而您提供的函数distance_of_the_shop实际上只需要一个参数。

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:

如果我理解正确,您希望distance_of_the_shop接收当前用户和正在进行比较的商店。要实现这一点,请使用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.

另请注意,调用sorted而不将其值赋给某个​​变量或容器是没有意义的。如果要对列表进行就地排序,请使用其排序方法,如上所示。

#3


1  

First, we need a distance function (this one calculates great-circle distances):

首先,我们需要一个距离函数(这个计算大圆距离):

from math import radians, cos, sin, asin, sqrt

def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points 
    on the earth (specified in decimal degrees)
    """
    # from *.com/questions/4913349/haversine-formula-in-python-bearing-and-distance-between-two-gps-points#4913653
    # convert decimal degrees to radians 
    lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])

    # haversine formula 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a)) 

    # 6367 km is the radius of the Earth
    km = 6367 * c
    return km

then we define a distance-function per user:

然后我们定义每个用户的距离函数:

def dist_from_user(user):
    # This is kind of funky, because the `user` parameter is
    #  not used, we simply assume that user is the current session-holder.
    # It would make more sense if we actually had more than
    #  one user to choose between.
    lat = float(request.session['user_latitude'])
    lon = float(request.session['user_longitude'])

    def shop_dist(shop):
        s_lat = float(shop.latitude)
        s_lon = float(shop.longitude)
        return haversine(lon, lat, s_lon, s_lat)
    return shop_dist

and call it like

并称之为

shop_list.sort(key=dist_from_user(user))

#1


10  

Just wrap the call in a lambda:

只需将调用包装在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.

并向distance_of_the_shop()函数添加两个参数以接收经度和纬度。

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.

sorted()函数为shop_list中的每个值调用键,但没有任何内容表示callable本身不能调用其他函数。 lambda是创建新包装函数的最简单方法。

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().

您还可以使用functools.partial()对象,前提是经度和纬度值可以作为关键字参数传递,或者将这两个值作为前两个位置参数接受。将它们作为关键字参数处理可能是最好的,即使给它们一个位置(没有默认值),你也可以在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)

而sorted()会将每个商店传递给partial(),而partial()又调用distance_of_the_shop(shop,long = ulong,lat = ulat)

#2


1  

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.

您的问题很难理解,因为您从未定义距离函数,而您提供的函数distance_of_the_shop实际上只需要一个参数。

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:

如果我理解正确,您希望distance_of_the_shop接收当前用户和正在进行比较的商店。要实现这一点,请使用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.

另请注意,调用sorted而不将其值赋给某个​​变量或容器是没有意义的。如果要对列表进行就地排序,请使用其排序方法,如上所示。

#3


1  

First, we need a distance function (this one calculates great-circle distances):

首先,我们需要一个距离函数(这个计算大圆距离):

from math import radians, cos, sin, asin, sqrt

def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points 
    on the earth (specified in decimal degrees)
    """
    # from *.com/questions/4913349/haversine-formula-in-python-bearing-and-distance-between-two-gps-points#4913653
    # convert decimal degrees to radians 
    lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])

    # haversine formula 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a)) 

    # 6367 km is the radius of the Earth
    km = 6367 * c
    return km

then we define a distance-function per user:

然后我们定义每个用户的距离函数:

def dist_from_user(user):
    # This is kind of funky, because the `user` parameter is
    #  not used, we simply assume that user is the current session-holder.
    # It would make more sense if we actually had more than
    #  one user to choose between.
    lat = float(request.session['user_latitude'])
    lon = float(request.session['user_longitude'])

    def shop_dist(shop):
        s_lat = float(shop.latitude)
        s_lon = float(shop.longitude)
        return haversine(lon, lat, s_lon, s_lat)
    return shop_dist

and call it like

并称之为

shop_list.sort(key=dist_from_user(user))