Reputation: 35
enumerate() for a list works as expected.
def swap(nums, i, j):
temp = nums[i]
nums[i] = nums[j]
nums[j] = temp
mylist = [0,1,22,33,4]
for pos, num in enumerate(mylist):
print(pos,num)
if pos == 0:
swap(mylist,2,3)
In this example, num
shows swapped value as expected.
0 0
1 1
2 33 <--
3 22 <--
4 4
But if I change mylist
to mylist[:-1]
like:
def swap(nums, i, j):
temp = nums[i]
nums[i] = nums[j]
nums[j] = temp
mylist = [0,1,22,33,4]
for pos, num in enumerate(mylist[:-1]):
print(pos,num)
if pos == 0:
swap(mylist,2,3)
num
does not show swapped value.
0 0
1 1
2 22 <--
3 33 <--
Why does this happen?
Upvotes: 1
Views: 559
Reputation: 26039
mylist[:-1]
is creating a new list object but you perform swap using mylist
.
How do you know it's a different object?
You can test this behaviour using id()
:
>>> mylist = [0,1,22,33,4,5]
>>> id(mylist)
3954492760
>>> lst = mylist
>>> id(lst)
3954492760
>>> sliced = mylist[:-1]
>>> id(sliced)
3954492920
If you observe, sliced
's id is different.
for pos, num in enumerate(mylist[:-1]):
print(pos,num)
if pos == 0:
swap(mylist,2,3)
# ^^^ - you used a different list object from what you were iterating over.
The easiest fix you can do is slice beforehand:
sliced = mylist[:-1]
for pos, num in enumerate(sliced):
print(pos,num)
if pos == 0:
swap(sliced,2,3)
So as others mentioned this has nothing to do with enumerate
.
Upvotes: 1
Reputation: 1123470
The difference is that you are enumerating on a copy of the list. In your first example, you are enumerating on a direct reference to the list that you are altering, but in the second example, you used slicing on the list to enumerate over. Slicing returns a new list object.
This is important because you are altering what not-yet-iterated-over positions are referencing to. List iteration uses an ever-increasing index to yield values, altering the list as you iterate can mean that a next index references a different value.
That the iteration is done via the enumerate()
function doesn't really matter. You'd have the same problem without enumerate()
:
for num in mylist:
print(num)
if num == 0:
swap(mylist, 2, 3)
would print
0
1
33
22
4
and slicing would give you a copy, so:
for num in mylist[:-1]:
print(num)
if num == 0:
swap(mylist, 2, 3)
outputs
0
1
22
33
If the goal is to skip the last element, then instead of creating a copy through slicing, you could use the enumerated position to break out of the loop early:
for pos, num in enumerate(mylist):
if pos == len(mylist) - 1:
break
print(pos, num)
if pos == 0:
swap(mylist, 2, 3)
or you can use the itertools.islice()
function
from itertools import islice
for pos, num in enumerate(islice(mylist, len(mylist) - 1)):
print(pos, num)
if pos == 0:
swap(mylist, 2, 3)
or you could simply create your copy first, then alter the indices of that copy:
sliced = mylist[:-1]
for pos, num in enumerate(sliced):
print(pos, num)
if pos == 0:
swap(sliced, 2, 3)
Upvotes: 1
Reputation: 3376
The problem doesn't come from the enumerate
function.
Actually, when doing mylist[:-1]
you are creating a new list, and working on it.
So when you try to modify your list (swap(mylist,2,3)
), you modify the original one, not the new one (created by mylist[:-1]
).
You can solve your problem by doing:
new_list = mylist[:-1]
for pos, num in enumerate(new_list):
print(pos,num)
if pos == 0:
swap(new_list,2,3)
Upvotes: 2