Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Introducing Lists Using Lists Mutability

questions regarding to the use of copy() and what really happen

Hi, so i had to experiment a bit to understand it better and i still have questions. lets look at this example:

list_of_letters = ["a", "b", "c", "d"]
for letter in list_of_letters:
    list_of_letters.remove(letter)
print(list_of_letters)

# we get this output -["b", "d"]

but when we iterate through a copy of list_of_letters:

list_of_letters = ["a", "b", "c", "d"]
for letter in list_of_letters.copy():
    list_of_letters.remove(letter)
print(list_of_letters)

#we get the intended  ouput: [] 

I want to understand what really happend here,if we follow the logic of the code,first we iterate through a copy of the list and then we REMOVE from the MASTER list, but my question is this: this is working because now we have a copy of the list and when later i print() the list i actually printing the MASTER LIST after we modified her?

i couldn't figured out why we dont remove from the copy list as well?

Steven Parker

KRIS NIKOLAISEN

Steven Parker
Steven Parker
231,236 Points

:bookmark: Hi, I was alerted by your tag, but I see Dave got here first and left an excellent response.

That makes a good point - there are lots of folks willing to help, so you might give the community a chance to respond to a new general knowledge question before tagging anyone specific.

11 Answers

Dave StSomeWhere
Dave StSomeWhere
19,870 Points

It is because the list's index values are mutable and are being modified in the for loop.

In your example A has an index of 0, B is 1, C is 2 and D is 3.

When you do a remove of the first letter, A, at index zero, the values change index values - resulting in B at index 0, C at index 1 and d at index 2.

Then your loop move on to index 1 (which is now C) and you remove it, skipping letter B. C is removed and D is now at index 1 and the loop move on to index 2 - which ends the loop - leaving B and D (skipping B and D).

By looping over the copy, the original index values are used and don't get messed up. Then when you do the remove method it removes by the value at that index. In copy index of 1 has a value of B and you remove the value of B at index 0 in the original list... and so on...

Try this code to assist is seeing what's happening (set the copy to a variable to see values):

list_of_letters = ["a", "b", "c", "d"]
copy_of_letters = list_of_letters.copy()
for letter in copy_of_letters:
    print("\nLetter is {}, list index is {} and copy index is {}".format(letter, list_of_letters.index(letter),
                                                                         copy_of_letters.index(letter)))
    list_of_letters.remove(letter)
print("\nfinal list of letters is --> ", list_of_letters)

#output
Letter is a, list index is 0 and copy index is 0

Letter is b, list index is 0 and copy index is 1

Letter is c, list index is 0 and copy index is 2

Letter is d, list index is 0 and copy index is 3

final list of letters is -->  []

Hopefully that helps.

I didnt understand ur example.. my main qustion was Do i use the remove() method on the copy() of the list or do i use the remove() method on the original list()

My hamster mind finally gets it! This is why I love passing over the questions after a video. To have a further analysis of what I learned and to use it in motion. evil squirrel laugh

tysm, dave! your explanation was super clear! all makes sense now! :)

Katie Ferencik
Katie Ferencik
1,775 Points

THANK YOU! Seeing it this way helps. Appreciate it!

Dave StSomeWhere

I run ur code, why the orginial list index is 0 evrey iteration?

Dave StSomeWhere
Dave StSomeWhere
19,870 Points

Because you just removed the letter at index 0 and the list changes and moves the next letter to index 0 - that's the key point of why you need to copy and why letters b and d are skipped in your first example.

Steven Parker
Steven Parker
231,236 Points

I'm flattered, both of you! :blush: And you will remove from the original list. The reason you want to use a copy of the list for the loop is to prevent the removals from causing other items to be skipped over. Dave was explaining how that happens.

Dave StSomeWhere Dave thanks for the coding example!, I wanted to know what happend in the loop and on what we use the remove() method.

i only have 1 more question: in my exmaple:

list_of_letters = ["a", "b", "c", "d"]
for letter in list_of_letters:
    list_of_letters.remove(letter)
print(list_of_letters)

# we get this output -["b", "d"]

i understand why we left with ["b", "d"], but i still have doubts with the remove() part. we remove "a" first and the list is now [ "b", "c", "d"] >> b is in index 0, c is in index 1 and d is in index 2, now the remove() method removes "c" because of what?, is it because he now remove the element in index 1 because he already removed the elemnt in index 0? remove() always start removing elements from the first index if we use remove in a for loop?

if u run this exmaple

list_of_letters = ["a", "b", "c", "d"]
for letter in list_of_letters:
    list_of_letters.remove(letter)
    print("You just removed {}".format(letter))
print(list_of_letters)

i see that a is removed and then we skip b and then c is removed , so remove() after he removes an element is moving to the next index

Steven Parker maybe u can answer my last question

Steven Parker
Steven Parker
231,236 Points

Don't be impatient, give Dave time to respond. :hourglass:

Dave StSomeWhere
Dave StSomeWhere
19,870 Points

Just give me a chance :smile:. Steven, your ability to succinctly answer questions and express concepts continues to be very helpful, informative and appreciated.

Sounds like your question is on the remove() and I think you are confusing the remove and the indexing of the loop.

The Doc for Remove state

list.remove(x) Remove the first item from the list whose value is equal to x. It raises a ValueError if there is no such item.

The remove is by value and not index. The loop is by index.

Does that answer your question? :tropical_drink: :palm_tree:

Dave StSomeWhere so in my example:

list_of_letters = ["a", "b", "c", "d"]
for letter in list_of_letters:
    list_of_letters.remove(letter)
    print("You just removed {}".format(letter))
print(list_of_letters)

so what exactly happen here, if remove() removes the first item from the list, then lets say >>> "a" is removed then "b" is now the value , then why he don't remove him?(why the behavior now is that "b" got skipped? I understand what list.remove() does and i understand what happend in the loop but i dont understand what do u mean by " Remove the first item from the list whose value is equal to x.",

in this example now "b" is equal to x and he don't get removed he got skipped so its not by value, if it was by value then why it got skipped?

if i dont iterate over a copy() of list_of_letters, first we itearte on "a" and "a" got removed, then we left with ["b","c",d"] no we on the next iteration which is in index 1 then "c" got skipped that's the behavior?

Dave StSomeWhere

Meow :]?^^^

Dave StSomeWhere
Dave StSomeWhere
19,870 Points

I think you are confusing the loop and the remove, and you need to keep them separate.

So, the loop will continue bumping up the index and move from letter to letter....

When looping over the copy (with your "a, b, c d") example, there are 4 items in the list with indexes from 0 to 3. By using a copy the loop sets the letter variable for each value. Then within the loop you do a remove based on the value. Issuing a remove() for the letter "a", will remove the first occurrence of the letter "a". If the list contained 3 entries with the value 'a" then the remove only removes the first one. Like - ["a", "b", "c", "d", "a", "q", "a"] - we have the value "a" at index 0, 4 and 6. remove('a') will only remove the one at index 0 (the first one, you would need to issue two more removes to get all three removed).

On your question:

if i dont iterate over a copy() of list_of_letters, first we itearte on "a" and "a" got removed, then we left with ["b","c",d"] no we on the next iteration which is in index 1 then "c" got skipped that's the behavior?

No, you mixing the loop and the remove - you need to keep them separate.

In the non-copy() example: The loop is bumping up the index.

First time through the loop - the loop starts at index 0 and updates the letter variable to "a" since that is the value at index 0. Then you issue a remove for the letter "a". The remove finds the first letter "a" at index 0 and removes it. Thus changing the list (the mutable part) and now the list contains b,c and d at index 0, 1 and 2.

Then we loop again. The index is bumped from 0 to 1 and the loop sets the letter variable to c (skipping "b" at index 0 - we're now on index 1 - this is the ah ha part). Now the letter variable is set to "c" and we do a remove (by value) on the letter "c". Changing the list again which now becomes "b" and "d" at index 0 and 1.

Then the loop bumps the index from 1 to 2 and ends because it is through the list - and the result is just b and d.

???

Dave StSomeWhere

Thanks :D i finally understand that part so when we loop over a copy() of the list we dont lose any elements in the list because we iterate over the first item in the copy() and then we remove the value from the original list and because remove() works by value i just remove the letter at that iteration!

gabrielle moran
gabrielle moran
1,985 Points

If you run your code through step by step on this site you can see that the progress of the loop always takes it back to the next index, not the one it has already done! http://pythontutor.com

T. W.
T. W.
1,479 Points

Read "Dave StSomeWhere's" response and explanation slowly and it will clear up confusion :)

Steven Parker I still didnt understand his solution. i find ur exaplnations very helpful, take it as a compliment :] my main qustion was Do i use the remove() method on the copy() of the list or do i use the remove() method on the original list()

Dave StSomeWhere
Dave StSomeWhere
19,870 Points

I also find Steven's answers very useful (and better) :smile:

I thought you were trying to understand what is happening in the loop and why we need to use a copy of the list.

Since the goal is to modify the original list.

You need to do the remove on the original list.

The copy is only used to maintain the proper indexing of the original list since the remove() method modifies the original list and will alter the behavior of the list. That is what I tried to display with the coding example.

Sorry to be so confusing. I'll be quiet now.