2016-10-03 5 views
-1

私は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) 

を私は"year":2016, "month":10, "day":2ため"energy"値を抽出する方法をここでは、JSONのように見えるものでしょうか?

+0

有効なJSONではありません。私は 'JSON ='がJSONテキスト文字列にないと仮定しています。 –

+1

ここには*解析に関する条項はありません。解析されたデータ構造を検索してその一部を抽出することは、条件付き解析(「CS研究の対象」の土地ではない)よりもはるかに簡単な問題です。 –

+0

ところで、これはむしろ不幸なデータ構造です。 {"year":{"2016":{"10":{"1":0.651、 "2":0.349、 "3"}の場合、単一の値を検索する方がはるかに効率的です。 ":0.481}}}' –

答えて

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) 
+0

ありがとうございます。それは完璧に動作します。 – Baobab

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