Search code examples
pythonlistdictionaryindexingnested

How to select a certain key from a dictionary in a list of another list?


I have a nested JSON-file that looks like this:

[
   {
      "IsRecentlyVerified": true,
      "AddressInfo": {
          "Town": "Haarlem",
      },
      "Connections": [
          {
             "PowerKW": 17,
             "Quantity": 1
          }
       ],
       "NumberOfPoints": 1,
    },
    {
      "IsRecentlyVerified": true,
      "AddressInfo": {
          "Town": "Haarlem",
      },
      "Connections": [
          {
             "PowerKW": 17,
             "Quantity": 1
          },
          {
             "PowerKW": 17,
             "Quantity": 1
          }
       ],
       "NumberOfPoints": 1,
    }
]

As you can see, the list of this JSON-file consists of two dictionaries that each contains another list (= "Connections") that consists of at least one dictionary. In each dictionary of this JSON-file, I want to select all keys named "Quantity" to make a sum with its value (so in the example code above, I want to calculate that there are 3 Quantities in total).

Sometimes, the key "Quantity" is not always present, so that's why I used in to check if it is present. I noticed that it now only finds the key "Quantity" when I mention the index, like this: if "Quantity" in ev_list[info]["Connections"][0]

def amountOfChargingStations():
    totalAmountOfChargingPolesInCity = 0

    for info in range(len(ev_list)):
        if "Town" in ev_list[info]["AddressInfo"]:
            if ev_list[info]["AddressInfo"]["Town"] == "Haarlem":
                totalAmountOfChargingStationsInCity = totalAmountOfChargingStationsInCity + 1

            if "Quantity" in ev_list[info]["Connections"][0]:
                if ev_list[info]["Connections"]:
                    for pole in ev_list[info]["Connections"]:
                        totalAmountOfChargingPolesInCity = totalAmountOfChargingPolesInCity + pole["Quantity"]
            else:
                print("Can't find connection")

    print("There are at least", totalAmountOfChargingPolesInCity, "charging poles available.")

polesAndStations = amountOfChargingStations()

The problem is that it now only uses the first dictionary of each "Connections"-list to make the sum. How can I select all keys named "Quantity" to make this sum, without knowing the total the amount of dictionaries in each "Connections"-list? (The total amount varies from 1 up to more than 10). Is there something like [0:end]?


Solution

  • as a oneliner:

    total_quantity = sum([con['Quantity'] for dataset in data for con in dataset['Connections'] if 'Connections' in dataset.keys() and 'Quantity' in con.keys() ])
    

    given datais your imported json.


    EDIT: sorry, did not read your code carefully enough.

    actually you do not need to be so complicated with the for loop over a range, sounds like you are coming from another programming language. With

    for info in ev_list
        ...
    

    you already get the element itself and can change ev_list[info] to info.

    Also did you get totalAmountOfChargingStationsInCity from somewhere else? It should return a 'referenced before assignment error' like this.

    I am still a fan of oneliners and list comprehensions, so this would do the trick for me:

    def amountOfChargingStations():
        total_amount_of_charging_poles_in_city = 0
        total_amount_of_charging_stations_in_city = 0
        for info in ev_list:
            if "Town" in info["AddressInfo"]:
                if info["AddressInfo"]["Town"] == "Haarlem":
                    total_amount_of_charging_stations_in_city = total_amount_of_charging_stations_in_city + 1
    
                total_amount_of_charging_poles_in_city += sum(
                    [con.get('Quantity', ) for con in info.get('Connections', [])])
        print("There are at least", total_amount_of_charging_poles_in_city, "charging poles available.")
    

    EDIT2: sorry, my mistake, changed the comprehension a bit. dictionary.get('key', 'default if key is not in dictionary') is a safer way to call something from a dictionary.