Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 625
Nguyen Anh Tan Avatar asked Dec 30 '20 03:12

Nguyen Anh Tan


People also ask

How to nested while loop in Python?

The syntax for nesting while loop in Python is: while (expression_1): #Outer loop [code to execute] #Optional while (expression_2): #Inner loop [code to execute] Unlike the for loop, the while loop doesn’t have a precompiled iterable sequence. While loop keeps executing the code until the expression evaluates to true.

Why are nested loops bad for programming?

Nested loops are not a bad thing per se. They are only bad, if there are used for problems, for which better algorithm have been found (better and bad in terms of efficiency regarding the input size). Sorting of a list of integers for example is such a problem. In your case above you have three lists, all of size 4.

What happens when you continue a loop in Python?

In Python, when the continue statement is encountered inside the loop, it skips all the statements below it and immediately jumps to the next iteration. In the following example, we have two loops. The outer for loop iterates the first list, and the inner loop also iterates the second list of numbers.

How to break out of a loop in Python?

Python can’t do this, but others can, such as the PHP: In PHP, the break keyword accepts an optional number which determines how many nested loops are to be broken out of. The default value is 1, which means to break out of the inner-most loop. It’s a very neat and clear solution.


Video Answer


3 Answers

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']
    )
like image 119
kaya3 Avatar answered Oct 23 '22 22:10

kaya3


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

like image 40
adarian Avatar answered Oct 23 '22 21:10

adarian


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)
like image 21
Headcrab Avatar answered Oct 23 '22 23:10

Headcrab