有条件地解析json

时间:2016-10-03 23:37:27

标签: python json

我正在尝试使用python从json数组中提取值。如何在特定日期获得"energy"的值?这是json的样子:

{
  "emeter": {
    "get_daystat": {
      "day_list": [
        { "year": 2016, "month": 10, "day": 1, "energy": 0.651000 },
        { "year": 2016, "month": 10, "day": 2, "energy": 0.349000 },
        { "year": 2016, "month": 10, "day": 3, "energy": 0.481000 }
      ],
      "err_code": 0
    }
  }
}

例如,使用:

parsed_json = json.loads(json)

如何提取"energy"的{​​{1}}值?

2 个答案:

答案 0 :(得分:3)

parsed_json将有一个python dict。您可以通过简单的线性搜索访问day_list数组。

def get_energy_value_by_date(obj, year, month, day):   
    for value in obj['emeter']['get_daystat']['day_list']:
        if value['year'] == year and value['month'] == month and value['day'] == day:
            return value['energy']


energy = get_energy_value_by_date(parsed_json, 2016, 10, 2)

答案 1 :(得分:0)

您可以对数据进行线性搜索:

def get_energy(data, year, month, day):
    for date in data['emeter']['get_daystat']['day_list']:
        if(date['year'] == year
           and date['month'] == month
           and date['day'] == day):
            return date['energy']

json_data = {
  "emeter": {
    "get_daystat": {
      "day_list": [
        { "year": 2016, "month": 10, "day": 1, "energy": 0.651000 },
        { "year": 2016, "month": 10, "day": 2, "energy": 0.349000 },
        { "year": 2016, "month": 10, "day": 3, "energy": 0.481000 }
      ],
      "err_code": 0
    }
  }
}

print('{:1.6f}'.format(get_energy(json_data, 2016, 10, 2)))  # --> 0.349000

如果没有匹配日期,该函数将有效返回None

<强> *更新*

如果您在"day_list" 中有很多天,他们按照您的示例所示按日期排序(排序),则可以更快地利用它并执行二分搜索而不是线性搜索。 Python包含bisect模块,可用于执行简单的二进制搜索。不幸的是,它中没有一个函数采用可选参数来控制比较,如sorted()函数。

但是,可以通过查看模块的source code并编写自己的搜索功能来解决这个问题,如下所示:

from datetime import datetime

def keyed_bisect_left(a, x, lo=0, hi=None, keyfunc=lambda v: v):
    """Return the index where to insert item x in list a, assuming a is sorted.

    Like bisect.bisect_left but allows a keyfunc to extract key from each item.
    """
    x_key = keyfunc(x)
    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi) // 2
        if keyfunc(a[mid]) < x_key:
            lo = mid+1
        else:
            hi = mid
    return lo

def get_date(d):
    return datetime(d['year'], d['month'], d['day'])

def get_energy2(data, year, month, day):
    """Locate the first day exactly equal to the given date."""
    day_list = data['emeter']['get_daystat']['day_list']
    target = {'year': year, 'month': month, 'day': day}

    i = keyed_bisect_left(day_list, target, keyfunc=get_date)

    # return energy value if date found
    if i != len(day_list) and get_date(day_list[i]) == get_date(target):
        return day_list[i]['energy']

    raise ValueError('date not found')

print('{:1.6f}'.format(get_energy2(json_data, 2016, 10, 1)))
print('{:1.6f}'.format(get_energy2(json_data, 2016, 10, 2)))
print('{:1.6f}'.format(get_energy2(json_data, 2016, 10, 3)))
print('{:1.6f}'.format(get_energy2(json_data, 2016, 10, 4)))

输出:

0.651000
0.349000
0.481000
Traceback (most recent call last):
  File "conditionally-parsing-json.py", line 67, in <module>
    print('{:1.6f}'.format(get_energy2(json_data, 2016, 10, 4)))  # --> ValueError
  File "conditionally-parsing-json.py", line 62, in get_energy2
    raise ValueError('date not found')
ValueError: date not found