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<noob />
17,062 Pointsquestions 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?
11 Answers
Dave StSomeWhere
19,870 PointsIt 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.
<noob />
17,062 PointsI 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()
Carlos Muñoz Sanchezllanes
4,407 PointsMy 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
tangybit
6,777 Pointstysm, dave! your explanation was super clear! all makes sense now! :)
Katie Ferencik
1,775 PointsTHANK YOU! Seeing it this way helps. Appreciate it!
<noob />
17,062 PointsI run ur code, why the orginial list index is 0 evrey iteration?
Dave StSomeWhere
19,870 PointsBecause 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
231,269 PointsI'm flattered, both of you! 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.
<noob />
17,062 PointsDave 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
<noob />
17,062 PointsSteven Parker maybe u can answer my last question
Steven Parker
231,269 PointsDon't be impatient, give Dave time to respond.
Dave StSomeWhere
19,870 PointsJust give me a chance . 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?
<noob />
17,062 PointsDave 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?
<noob />
17,062 PointsMeow :]?^^^
Dave StSomeWhere
19,870 PointsI 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.
???
<noob />
17,062 PointsThanks :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
1,985 PointsIf 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.
1,479 PointsRead "Dave StSomeWhere's" response and explanation slowly and it will clear up confusion :)
<noob />
17,062 PointsSteven 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
19,870 PointsI also find Steven's answers very useful (and better)
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.
Steven Parker
231,269 PointsSteven Parker
231,269 PointsHi, 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.