除了正则表达式之外,还有更好的方法来分割这个JSON字符串吗?

时间:2016-02-17 17:57:37

标签: python json

我正在研究车辆路径问题,到目前为止,最耗时的部分是使用真实的道路网络生成距离/时间矩阵。对于这个项目,我使用localhost graphhopper服务器,我曾经用它来获得成对距离和位置之间的时间;一切都很容易解析。它返回单独的驾驶指令以及总行程距离和时间。但是,对于2000个地点,这将是接近4千万的电话。

在预感到的时候,我想知道如果我要求它改为计划一次通过100个地点的路线会更快。然后目标是将json响应分解为100个块,就像我已经进行了100次成对调用一样。事实证明,它对于100个地点来说快了近3倍。除了试图跟踪我的矩阵的哪些部分被构建时有点头痛,响应没有为每个子路径提供明显的结构差异,而只是给出了你在“停留”的指令,例如

{
    "hints": {
        "visited_nodes.average": "243.0",
        "visited_nodes.sum": "3402"
    },
    "paths": [{
        "instructions": [{
            "distance": 315.637,
            "sign": 0,
            "interval": [0, 7],
            "text": "Continue",
            "time": 29848
        }, {
            "exit_number": 3,
            "distance": 1460.234,
            "sign": 6,
            "turn_angle": -0.01,
            "interval": [7, 27],
            "text": "At roundabout, take exit 3",
            "time": 96167
        }, {
            "distance": 1258.763,
            "sign": 0,
            "interval": [27, 30],
            "text": "Continue onto Sheikh Zayed bin Sultan Street",
            "time": 50350
        }, {
            "distance": 116.7,
            "sign": 0,
            "interval": [30, 31],
            "text": "Continue",
            "time": 4668
        }, {
            "distance": 3543.556,
            "sign": 0,
            "interval": [31, 57],
            "text": "Continue onto Sheikh Zayed bin Sultan Street",
            "time": 144812
        }, {
            "distance": 0,
            "sign": 5,
            "interval": [87, 88],
            "text": "Stopover 1",
            "time": 0
        },

我目前的工作原型是对每条指令的各个距离(米)进行汇总,但在重新开始记录距离之前使用正则表达式来寻找“中途停留”。

distance_matrix = []
sub_distance = []
for unit in response['paths'][0]['instructions']:
    if bool(re.search('Stopover', unit['text'])) == False:
        sub_distance.append(float(unit['distance'])/1000)
    else:
        distance_matrix.append(sum(sub_distance))
        sub_distance = []

我的背景不是编程,我在Python中自学成才不到一年。虽然这有效,但我想知道我是否错过了一种更自然(更快)的方式来做到这一点,但我找不到任何与谷歌相关的东西,因为我不太确定我在寻找什么。在我们目前的尺度上,距离/时间矩阵已经需要大约8分钟来计算,所以我愿意接受任何削减时间的建议。路线中的点数似乎有限,因此此功能仍会被调用数千次,因此它会累加起来。提前谢谢。

3 个答案:

答案 0 :(得分:2)

你有没有理由存储子距离列表?如果您所做的只是计算总和,那么在我看来这样做会更快:

distance_matrix = []
sub_distance = 0.0
for unit in response['paths'][0]['instructions']:
    if not unit['text'].startswith('Stopover'):
        sub_distance += unit['distance']
    else:
        distance_matrix.append(sub_distance / 1000.0)
        sub_distance = 0.0

小型性能测试:

import re
import timeit
import random

# Creates a list of 1000000 items with random distances from [0, 1). On average every 10th element will be a stopover.
data = [{"distance": random.random(), "text": "Stopover" if random.randint(0, 10) == 0 else "ASDF"} for i in range(1000000)]

def test1():
  distance_matrix = []
  sub_distance = 0.0
  for unit in data:
    if not unit['text'].startswith('Stopover'):
      sub_distance += unit['distance']
    else:
      distance_matrix.append(sub_distance / 1000.0)
      sub_distance = 0.0

  return distance_matrix

def test2():
  distance_matrix = []
  sub_distance = []
  for unit in data:
    if bool(re.search('Stopover', unit['text'])) == False:
      sub_distance.append(float(unit['distance'])/1000)
    else:
      distance_matrix.append(sum(sub_distance))
      sub_distance = []

  return distance_matrix

print "Test 1: %.2f s for 10 runs" % timeit.timeit(test1, number=10)
print "Test 2: %.2f s for 10 runs" % timeit.timeit(test2, number=10)

在我的机器上产生以下内容:

$ python test.py
Test 1: 3.50 s for 10 runs
Test 2: 16.67 s for 10 runs

顺便说一句,我应该提到预编译的正则表达式几乎和使用startswith()一样快,这在其他时候可以派上用场。

在之外预编译循环,如下所示:

stop = re.compile("Stopover")

在循环中使用如下:

if not stop.search(unit['text']):

答案 1 :(得分:1)

在这里使用正则表达式没有多大意义,因为您没有使用它的任何功能。在这里使用startswith会更简单,也可能更快。

if unit['text'].startswith('Stopover'):

请注意,您不应该明确地将布尔值与False进行比较,只需执行if <condition>:

答案 2 :(得分:1)

我同意丹尼尔,你不需要正则表达式来做你想做的事。

如果您的说明以您要搜索的命令(例如中途停留)开头,请使用.startswith方法。

如果您要查看的说明不在字符串的开头,则可以使用与正则表达式类似的unit['text'].find('stopover'),或者用于进一步简化搜索用途:

distance_matrix = []
sub_distance = []
for unit in response['paths'][0]['instructions']:
    if 'Stopover' in unit['text']:
        distance_matrix.append(sum(sub_distance))
        sub_distance = []
    else:
        sub_distance.append(float(unit['distance'])/1000)

字符串搜索不能快得多,你不会在程序的这一部分看到任何非常重要的加速。

编辑: 刚刚找到this问题解释了一些考虑字符串搜索的性能问题。看看吧。