Nguyen Anh Tan
Nguyen Anh Tan

Reputation: 63

Python, Avoid ugly nested for loop

I'm new to python programming. I have tried a lot to avoid these nested for loops, but no success.

My data input like:

[
  {
    "province_id": "1",
    "name": "HCM",
    "districts": [
      {
        "district_id": "1",
        "name": "Thu Duc",
        "wards": [
          {
            "ward_id": "1",
            "name": "Linh Trung"
          },
          {
            "ward_id": "2",
            "name": "Linh Chieu"
          }
        ]
      },
      {
        "district_id": "2",
        "name": "Quan 9",
        "wards": [
          {
            "ward_id": "3",
            "name": "Hiep Phu"
          },
          {
            "ward_id": "4",
            "name": "Long Binh"
          }
        ]
      }
    ]
  },
  {
    "province_id": "2",
    "name": "Binh Duong",
    "districts": [
      {
        "district_id": "3",
        "name": "Di An",
        "wards": [
          {
            "ward_id": "5",
            "name": "Dong Hoa"
          },
          {
            "ward_id": "6",
            "name": "Di An"
          }
        ]
      },
      {
        "district_id": "4",
        "name": "Thu Dau Mot",
        "wards": [
          {
            "ward_id": "7",
            "name": "Hiep Thanh"
          },
          {
            "ward_id": "8",
            "name": "Hiep An"
          }
        ]
      }
    ]
  }
]

And my code is:

for province in data:
    for district in province['districts']:
        for ward in district['wards']:
            # Excute my function
            print('{}, {}, {}'.format(ward['name'], district['name'], province['name']))

Output

Linh Trung, Thu Duc, HCM
Linh Chieu, Thu Duc, HCM
Hiep Phu, Quan 9, HCM
...

Even though my code is working it looks pretty ugly.
How can I avoid these nested for loops?

Upvotes: 6

Views: 271

Answers (3)

Headcrab
Headcrab

Reputation: 7103

You could do something like this:

def print_district(district, province):
    for ward in district['wards']:
        print('{}, {}, {}'.format(ward['name'], district['name'], province['name']))

def print_province(province):
    for district in province['districts']:
        print_district(district, province)

for province in data:   
    print_province(province)

Upvotes: 2

kaya3
kaya3

Reputation: 51037

Your data structure is naturally nested, but one option you have for neatening your code is to write a generator function for iterating over it:

def all_wards(data):
    for province in data:
        for district in province['districts']:
            for ward in district['wards']:
                yield province, district, ward

This function has the same triply-nested loop in it as you currently have, but everywhere else in your code, you can now iterate over the data structure with a single non-nested loop:

for province, district, ward in all_wards(data):
    print('{}, {}, {}'.format(ward['name'], district['name'], province['name']))

If you prefer to avoid having too much indentation, here's an equivalent way to write the function, similar to @adarian's answer but without creating a temporary list:

def all_wards(data):
    return (
        province, district, ward
        for province in data
        for district in province['districts']
        for ward in district['wards']
    )

Upvotes: 9

adarian
adarian

Reputation: 395

Here is a one-liner version

[
    print("{}, {}, {}".format(ward["name"], district["name"], province["name"]))
    for province in data
    for district in province["districts"]
    for ward in district["wards"]
]

Upvotes: 1

Related Questions