Python Introducing Lists Using Lists Review Mutability

this code its to confusing

all_restaurants = [
    "Taco City",
    "Burgertown",
    "Tacovilla",
    "Hotdog station",
    "House of tacos",
 ]

     def tacos_only(restaurants):
         taco_joints = restaurants.copy()
      for taco_joint in taco_joints.copy():
        if "taco" not in taco_joint.lower():
            taco_joints.remove(taco_joint)
       return taco_joints

dinner_options = tacos_only(all_restaurants)
John Lack-Wilson
John Lack-Wilson
8,163 Points

Hi Tim, could you be more specific about which part is causing the confusion?

3 Answers

Steven Parker
Steven Parker
200,430 Points

You don't have to completely understand the sample program to answer the question. The question is about general loop issues.

A good rule to remember is to never modify an iterable inside the loop it is controlling, it can cause side effects.

Viraj Deshaval
Viraj Deshaval
4,874 Points

Ok let me explain you bit by bit.

How it works is as below:

# Step - 1: Variable 'all_restaurants' is created with list of restaurant names. This is straight forward.
all_restaurants = [
    "Taco City",
    "Burgertown",
    "Tacovilla",
    "Hotdog station",
    "House of tacos",
 ]

# Step - 2: Defined a function name 'tacos_only' and passed a single argument to the function 'all_restaurants' in function parameter 'restaurants'.
     def tacos_only(restaurants):
# Step - 3: Confusing part is here, so what we need to do now is we want to remove the restaurants from the 
# 'all_restaurants' list by using the '.remove()' method. If I try to remove the restaurants from the all_restaurants list by iterating through each element then indexing gets changed. see below how it works:
# What I did is I have added the "Mc Donalds' at index 1. See how it works without copy as below
all_restaurants = [
    "Taco City", # index: 0
    "Mc Donalds", # index: 1
    "Burgertown", # index: 2
    "Tacovilla", # index: 3
    "Hotdog station", # index: 4
    "House of tacos", # index: 5
 ]

# I will run a for loop to loop over all the element in the list so now

Iteration - 1: At index = 0
taco_joint = "Taco City"
    if "taco" not in taco_joint.lower():
        all_restaurants.remove(taco_joint)
It found taco in the string "Taco City" so it will not remove the string

Iteration - 2: At index = 1
taco_joint = "Mc Donalds"
    if "taco" not in taco_joint.lower():
        all_restaurants.remove(taco_joint)
Did'nt found "taco" in string "Mc Donalds" so remove the element "Mc Donalds" from index 1. So when it removed the "Mc Donalds" list element gets shifted so 'all_restaurants' looks like below:

all_restaurants = [
    "Taco City", # index: 0
    "Burgertown", # index: 1
    "Tacovilla", # index: 2
    "Hotdog station", # index: 3
    "House of tacos", # index: 4
 ]

Iteration - 3: Now if I loop through the new all_restaurant list it will skip through the "Burgertown" resides at index 1. So it will never check the if condition for 'Burgertown'
at index 2
taco_joint = "Tacovilla"
for taco_joint in all_restaurants:
    if "taco" not in taco_joint.lower():
        all_restaurants.remove(taco_joint)
if found "taco" in string name "Tacovilla" so it was not remvoed.

O/p: ['Taco City', 'Burgertown', 'Tacovilla', 'House of tacos']

To resolve this, we create a 2 copy of the list "all_restaurants" and assigned it to variable "taco_joints" 
          1). First copy is to remove the element from the list
          2). Second copy is to only iterating over the list
         taco_joints = restaurants.copy() # this is the first copy from which we only remove the elements
      for taco_joint in taco_joints.copy(): # this is the second copy from which we only loop over the elements
        if "taco" not in taco_joint.lower():
            taco_joints.remove(taco_joint)
       return taco_joints

dinner_options = tacos_only(all_restaurants)

So how it works as below using copy:

all_restaurants = [
    "Taco City", # index: 0
    "Mc Donalds", # index: 1
    "Burgertown", # index: 2
    "Tacovilla", # index: 3
    "Hotdog station", # index: 4
    "House of tacos", # index: 5
 ]

taco_joints = all_restaurants.copy()
      for taco_joint in taco_joints.copy():
        if "taco" not in taco_joint.lower():
            taco_joints.remove(taco_joint)

Iteration - 1: Loop over the second copy of the list
At index = 0
taco_joint = "Taco City"
    if "taco" not in taco_joint.lower():
        all_restaurants.remove(taco_joint)
It found taco in the string "Taco City" so it will not remove the string

Iteration - 2: Loop over the second copy of the list
At index = 1
taco_joint = "Mc Donalds"
    if "taco" not in taco_joint.lower():
        all_restaurants.remove(taco_joint)
Did'nt found "taco" in string "Mc Donalds" so remove the element "Mc Donalds" from index 1 from "taco_joints" list (first copy of the list). So when it removed the "Mc Donalds" list element gets shifted so 'taco_joints' looks like below:

taco_joints = [
    "Taco City", # index: 0
    "Burgertown", # index: 1
    "Tacovilla", # index: 2
    "Hotdog station", # index: 3
    "House of tacos", # index: 4
 ]

Notice here second copy of the 'taco_joints' remain unchanged and no element shifted.

Iteration - 3: Loop over the second copy of the list 
Now if I loop through the list 'taco_list.copy()' (second copy of the list) it will not skip through the "Burgertown" resides at index 1. So it will check the if condition for 'Burgertown'
at index 2
taco_joint = "Burgertown"
for taco_joint in all_restaurants:
    if "taco" not in taco_joint.lower():
        all_restaurants.remove(taco_joint)
No taco in Burgertown it will not remove

I hope this helps

Hey Viraj. Thank you very much for this. is making more sense to me now. I was getting frustrated and could not understand it. once again Thank you.

Viraj im looking to buy a python book for begginers. What would you recommend. if you do. there are a lot of books out there Thanks in advance.

Hey Viraj. Thank you very much for this. is making more sense to me now. I was getting frustrated and could not understand it. once again Thank you.