【问题标题】:Omitting values from certain keys in a dict省略字典中某些键的值
【发布时间】:2011-03-29 22:11:39
【问题描述】:

我目前正在构建一个基于位置的服务,该服务可以为共享汽车的用户计算前往特定活动的路线。为了计算最短距离,需要知道用户之间的行驶距离,因为系统的一个约束条件是每个驾驶员不得超过一定的距离来接载特定的乘客.为了避免为同一条路线调用两次 Google Maps API,我在程序的开头填充了一个字典来存储距离。距离是这样生成的:

def generateDistances(self):
    users = self.drivers + self.passengers
    for user1 in users:
        for user2 in users:
            if user1 != user2:
                distance = GetDistance(user1.location, user2.location)
                self.distances.append({'Start' : user1, 'End' : user2, 'Distance' : distance['Distance']['meters'], 'Duration': distance['Duration']['seconds']})
        self.distances.append({'Start' : user1, 'End' : self.destination, 'Distance' : distance['Distance']['meters'], 'Duration': distance['Duration']['seconds']})

GetDistance 方法只是根据它们的纬度和经度从 Google Maps API 获取两个位置之间的路线。然后程序调用以下函数在字典中查找距离:

def getSavedDistance(self, user1, user2):
    if user1 == user2:
        return 0
    for record in self.distances:
        if record['Start'] == user1:
            if record['End'] == user2:
                return record['Distance']
    logging.warn("No distance from %s to %s found" % (user1.userid, user2.userid))

但是,我一直在 Google App Engine 上运行它并且运行速度非常慢,正如您可以想象的那样,随着问题规模的增加(即更多用户),运行时间呈指数增长。我想要做的是用每个用户之间的直线距离初始化dict(数学计算,不需要API调用),当系统测试路线的长度时,它会首先测试直线距离。如果直线距离大于最大距离,则路线太长 - 不需要计算实际距离。否则,系统只会看到行驶距离不在字典中,并进行必要的 API 调用以将其放入其中。

所以,我想出了类似这样的方法来初始化距离(请注意,这不起作用,因为我无法将 null 插入到 dict 值中):

def initialiseDistances(self):
    users = self.drivers + self.passengers
    for user1 in users:
        for user2 in users:
            if user1 != user2:
                self.distances.append({'Start' : user1, 'End' : user2, 'Distance' : null, 'Duration' : null, 'StraightLine' : GetStraightLineDistance(user1.location, user2.location)})
        self.distances.append({'Start' : user1, 'End' : self.destination, 'Distance' : null, 'Duration' : null, 'StraightLine' : GetStraightLineDistance(user1.location, self.destination)})

...然后 getSavedDistance 方法可以更改为这样的:

def getSavedDistance(self, user1, user2):
    if user1 == user2:
        return 0
    for record in self.distances:
        if record['Start'] == user1:
            if record['End'] == user2:
                if record['Distance'] == null:
                    distance = GetDistance(user1.location, user2.location)
                    record['Distance'] = distance['Distance']['meters']
                    record['Duration'] = distance['Duration']['seconds']
                    return record['Distance']
    logging.warn("No distance from %s to %s found" % (user1.userid, user2.userid))

这将允许系统仅填充实际使用的距离值,并避免两次调用相同的 API。但是,显然我不能将 null 插入到 dict 值中。有没有人知道我可以在这个字典中插入一些值来告诉我距离没有价值的方法?

谢谢

【问题讨论】:

  • 你喜欢任何答案吗?

标签: python google-maps dictionary


【解决方案1】:

使您的self.distances 成为一个字典,将 (start_user, end_user) 元组映射到您想要的信息。您正在做的事情涉及对 list 项的 O(N) 访问仅用于单个查找,而不是仅 1 dict 查找。使用 dict,如果您没有 (user1, user2) 的任何信息,则无需浪费时间和内存将虚拟“null”条目放入数据结构中。

info = self.distances_DICT.get((user1, user2))
if info is None: 
    self.calculate_the_distance_or_whatever_else_you_need_to_do(user1, user2))

【讨论】:

    【解决方案2】:

    由于这是 Python,None 是空值。与 None 相比,使用 is None,而不是 == None

    【讨论】:

      【解决方案3】:

      我可以建议一种不同的方法吗?使用 (user1, user2) 使您的 self.distances 成为一个字典,这会将您的查找从 O(n) 更改为 O(1)。假设GetDistance(user1, user2)GetDistance(user2, user1) 相同,您可以确保用作字典键的每个元组都已排序,以便您可以为每个方向重复使用相同的值。


      扩展 John Machin 的观点,用 Python 编写类似内容的惯用方式可能如下所示:

      class DistanceFinder(object):
          distances = {}
          def GetDistance(self, user1, user2):
              userkey = (user1, user2)
              if userkey in self.distances:
                  return self.distances[userkey]
              result = [... calculations go here ...]
              self.distances[userkey] = result
              return result
      

      Python 3.2 中的有趣工作:

      from functools import lru_cache
      class DistanceFinder:
          @lru_cache(maxsize=None)
          def GetDistance(self, user1, user2):
              return [... calculations go here ...]
      

      缓存的东西是内置的。不错吧?

      【讨论】:

      • 有些人:不是一个有效的假设(单行道、禁止左/右转标志等)
      • 优秀的分数。我想我的咖啡已经喝完了一天了。回到我们的共同点:使用带有(有序!)元组作为键的字典。
      • 一些观察结果:(1) 对于地理距离,d(a,b) == d(b,a)。 (2) 对于单向街道等问题:有必要为 N 向路口 (N >= 2) 中的每条街道 i 记录沿街道 i 接近路口的车辆是否被允许通过以下路口离开路口j街带有中间带防止转弯的街道需要被视为 2 x 单向街道。我认为谷歌地图没有足够的此类数据。我确实知道它会选择一条从我家到火车站的路线,该路线穿过一条狭窄的行人专用车道。
      • 哈!我听说过这样的路线,嗯,未优化。那里有 很好的地图包——我的公司非常依赖一个——但他们并没有完全放弃它们。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-15
      • 2011-05-27
      相关资源
      最近更新 更多