JvW
JvW

Reputation: 45

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]?

Upvotes: 1

Views: 91

Answers (4)

sk3k
sk3k

Reputation: 36

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.

Upvotes: 1

Deepak Tripathi
Deepak Tripathi

Reputation: 3233

using jmespath you can get sum as

import jmespath
print(sum(jmespath.search("[*].Connections[].Quantity", data), 0))

Upvotes: 1

Adon Bilivit
Adon Bilivit

Reputation: 26870

Here's a simple approach that, given the structure of your JSON as described, works as required:

quantity = 0

for d in json.loads(JDATA):
    if (_list := d.get('Connections')):
        for _d in _list:
            quantity += _d.get('Quantity', 0)

print(quantity)

Output:

3

Upvotes: 1

Andrej Kesely
Andrej Kesely

Reputation: 195408

You can try recursion:

import json


def get_quantity(o):
    if isinstance(o, dict):
        if "Quantity" in o:
            yield o["Quantity"]
        for v in o.values():
            yield from get_quantity(v)
    elif isinstance(o, list):
        for v in o:
            yield from get_quantity(v)


with open("your_file.json", "r") as f_in:
    data = json.load(f_in)

print(sum(get_quantity(data)))

Prints:

3

Upvotes: 1

Related Questions