conditionally parsing json
<p>I am trying to extract a value from a json array using python. How do I get the value for <code>"energy"</code> on a specific day? Here is what the json looks like:</p>

<pre><code>{
  "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
    }
  }
}
</code></pre>

<p>So for example, using:</p>

<pre><code>parsed_json = json.loads(json)
</code></pre>

<p>how would I extract the <code>"energy"</code> value for <code>"year":2016, "month":10, "day":2</code>?</p>

<p>You could do a linear search through the data:</p>

<pre><code>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)))  # --&gt; 0.349000
</code></pre>

<p>If there's no matching date, the function will effectively return <code>None</code>.</p>

<p><strong>*Update*</strong></p>

<p>If you have a lot of days in the <code>"day_list"</code> <em>and</em> they are ordered (sorted) by date as shown in your example, it would faster to take advantage of that and do a binary search rather than a linear one. Python includes the <a href="https://docs.python.org/2/library/bisect.html#module-bisect" rel="nofollow"><code>bisect</code></a> module, which can be used to do simple binary searches. Unfortunately none of the functions in it take optional arguments for controlling the comparisons like the <a href="https://docs.python.org/2/library/functions.html#sorted" rel="nofollow"><code>sorted()</code></a> function does.</p>

<p>However this can be overcome by looking at the <a href="https://hg.python.org/cpython/file/2.7/Lib/bisect.py#l67" rel="nofollow">source code</a> for the module and writing your own search function as illustrated below:</p>

<pre><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 &lt; 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo &lt; hi:
        mid = (lo+hi) // 2
        if keyfunc(a[mid]) &lt; 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)))
</code></pre>

<p>Output:</p>

<pre class="lang-none prettyprint-override"><code>0.651000
0.349000
0.481000
Traceback (most recent call last):
  File "conditionally-parsing-json.py", line 67, in &lt;module&gt;
    print('{:1.6f}'.format(get_energy2(json_data, 2016, 10, 4)))  # --&gt; ValueError
  File "conditionally-parsing-json.py", line 62, in get_energy2
    raise ValueError('date not found')
ValueError: date not found
</code></pre>

python json