nosense
nosense

Reputation: 200

variable scope under while+for loop and if statement

The purpose of this code is trying to output the route where the second element of one tuple is the same as the first element of another tuple.

When the i += 1 has the same indentation as for loop, "JFK" is the origin, path = segments. I got ['JFK', 'DEN', 'SFO', 'LAS', 'LAX', 'ORD', 'ATL'] which is the correct answer.

When i += 1 has the same indentation as if statement, I only got ['JFK', 'DEN', 'SFO', 'LAS']. Does anyone know why???

segments = [
            ("JFK", "DEN"),
            ("DEN", "SFO"),
            ("SFO", "LAS"),
            ("LAS", "LAX"),
            ("LAX", "ORD"),
            ("ORD", "ATL"),
            ("ATL", "JFK"),
]

def get_route(path, origin):
    my_list = []
    i = 0
    list_len = len(path)
    path_copy = path.copy()

    while i <= list_len:
        for k in path_copy:
            if origin == k[0] and origin not in my_list:
                my_list.append(k[0])
                origin = k[1]
                path_copy.remove(k)
        i += 1
    return my_list

get_route(segments, "JFK")

Upvotes: 0

Views: 67

Answers (2)

brandonwang
brandonwang

Reputation: 1643

If the i += 1 statement has the same indentation as the if statement (it's in the for loop), then your program will miss a few path nodes. This is because if the if statement is evaluated as false, i will be incremented but you wouldn't have appended to the path list.

Even with the i += 1 outside of the for loop, it serves no purpose. When I ran the code, path_copy became empty when i = 4, but i continues to increment until it reaches 7 in your case. Here is an updated version of your code that might work for you.

def get_route(path, origin):
    my_list = []
    list_len = len(path)
    path_copy = path.copy()

    while len(my_list) < list_len:
        for k in path_copy:
            if origin == k[0] and origin not in my_list:
                my_list.append(k[0])
                origin = k[1]
                path_copy.remove(k)
    return my_list

Upvotes: 1

e4c5
e4c5

Reputation: 53734

Well your intention is to loop as many times as there are elements in the list. If that is the case i +1 is at the right indentation level. Each iteration of the while loop results in i being increased by one.

Now if you moved that statement four spaces to the right, i is incremented during each iteration of the inner four loop. That means that variable gets incremented much more frequently than it should and the result differs from what you expect.

As a side note, this sort of loop is rather unusual in python. There are more usual ways of writing this.

def get_route(path, origin):

    my_list = []
    path_copy = path.copy()

    for _ in path:
        for k in path_copy:
            if origin == k[0] and origin not in my_list:

                my_list.append(k[0])

                origin = k[1]

                path_copy.remove(k)

         i += 1

    return my_list

I am not even really sure if you need a nested loop here. There's probably a better way of writing this whole method.

Upvotes: 1

Related Questions