简体   繁体   中英

How to extract the value of a given key based on the value of another key, from a list of nested (not-always-existing) dictionaries [Python]

I have a list of dictionaries called api_data , where each dictionary has this structure:

{

'location': 
    {
    'indoor': 0, 
    'exact_location': 0, 
    'latitude': '45.502', 
    'altitude': '133.9', 
    'id': 12780, 
    'country': 'IT', 
    'longitude': '9.146'
    },

'sampling_rate': None, 
'id': 91976363, 
'sensordatavalues': 
    [   
        {
        'value_type': 'P1', 
        'value': '8.85', 
        'id': 197572463
        }, 


        {
        'value_type': 'P2', 
        'value': '3.95', 
        'id': 197572466
        }

        {
        'value_type': 'temperature', 
        'value': '20.80', 
        'id': 197572625
        }, 

        {
        'value_type': 'humidity', 
        'value': '97.70', 
        'id': 197572626
        }
    ], 

'sensor': 
    {
    'id': 24645, 
    'sensor_type': 
        {
        'name': 'DHT22', 
        'id': 9, 
        'manufacturer': 
        'various'
        }, 

    'pin': '7'
    }, 

'timestamp': '2020-04-18 18:37:50'

},

This structure is not complete for each dictionary, meaning that sometimes a dictionary, a list element or a key is missing.

I want to extract the value of a key when the key value of the same dictionary is equal to a certain value.
For example, for dictionary sensordatavalues , I want the value of the key 'value' when 'value_type' is equal to 'P1' .

I have developed this code working with for and if cycles, but I bet it is heavily inefficient. How can I do it in a quicker and more efficient way?

Please note that sensordatavalues always exists

for sensor in api_data:

    sensordatavalues = sensor['sensordatavalues']
    # L_sdv = len(sensordatavalues)

    for physical_quantity_recorded in sensordatavalues:

        if physical_quantity_recorded['value_type'] == 'P1':

            PM10_value = physical_quantity_recorded['value']               

You just need one for loop:

for x in api_data["sensordatavalues"]:
    if x["value_type"] == "P1":
        print(x["value"])

Output:

8.85

Use dictionary.get() method if the key not exist it will return default value

for physical_quantity_recorded in api_data['sensordatavalues']:
    if physical_quantity_recorded.get('value_type', 'default_value') == 'P1':
        PM10_value = physical_quantity_recorded.get('value', 'default_value')
  1. If you are confident that the value 'P1' is unique to the key you are searching, you can use the 'in' operator with dict.values()
  2. Should be ok to omit this assignment: sensordatavalues = sensor['sensordatavalues']
for sensor in api_data:

    for physical_quantity_recorded in sensor['sensordatavalues']:

        if 'P1' in physical_quantity_recorded.values():

            PM10_value = physical_quantity_recorded['value'] 

this is an alternative: jmespath - allows you to search and filter a nested dict/json:

summary of jmespath... to access a key, use the . notation, if ur values are in a list, u access it via the [] notation

NB: dict is wrapped in a data variable

import jmespath
#sensordatavalues is a key, so we can access it directly
#the values of sensordatavalues are wrapped in a list
#to access it we pass the bracket(```[]```)
#we are interested in the dict where value_type is P1
#in jmespath, we identify that using the ? mark to precede the filter object
#pass the filter
#and finally access the key we are interested in ... value

expression = jmespath.compile('sensordatavalues[?value_type==`P1`].value')
expression.search(data)
['8.85']

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM