Is a new copy of array formed when passed as a slice to enumerate()? This is my guess after running the following experiments. It seems to me that's the case but I'm not sure how to prove my thinking with code?
Below is a code snippet and 2 results. The results corresponding to option A and option B are as follows as well.
def selection_sort(arr):
# for idx, item in enumerate(arr[:-1]): # option A
for idx, item in enumerate(arr): # option B
curr_min = item
swap_ptr = idx
print('========================================')
print('curr_min: {}'.format(curr_min))
print('arr before: {}'.format(arr))
for j in range(idx 1, len(arr)):
print('for item {}'.format(arr[j]))
if arr[j] < curr_min:
print('{} < {}'.format(arr[j], curr_min))
curr_min = arr[j]
swap_ptr = j
print('swap_ptr now at {} pointing to {}'.format(swap_ptr, curr_min))
(arr[idx], arr[swap_ptr]) = (arr[swap_ptr], arr[idx])
print('arr after: {}'.format(arr))
return arr
print(selection_sort([5,9,1,3,0,20,77,46]))
Result from running on option A (i.e. having option B commented out):
========================================
curr_min: 5
arr before: [5, 9, 1, 3, 0, 20, 77, 46]
for item 9
for item 1
1 < 5
swap_ptr now at 2 pointing to 1
for item 3
for item 0
0 < 1
swap_ptr now at 4 pointing to 0
for item 20
for item 77
for item 46
arr after: [0, 9, 1, 3, 5, 20, 77, 46]
========================================
curr_min: 9
arr before: [0, 9, 1, 3, 5, 20, 77, 46]
for item 1
1 < 9
swap_ptr now at 2 pointing to 1
for item 3
for item 5
for item 20
for item 77
for item 46
arr after: [0, 1, 9, 3, 5, 20, 77, 46]
========================================
curr_min: 1
arr before: [0, 1, 9, 3, 5, 20, 77, 46]
for item 3
for item 5
for item 20
for item 77
for item 46
arr after: [0, 1, 9, 3, 5, 20, 77, 46]
========================================
curr_min: 3
arr before: [0, 1, 9, 3, 5, 20, 77, 46]
for item 5
for item 20
for item 77
for item 46
arr after: [0, 1, 9, 3, 5, 20, 77, 46]
========================================
curr_min: 0
arr before: [0, 1, 9, 3, 5, 20, 77, 46]
for item 20
for item 77
for item 46
arr after: [0, 1, 9, 3, 5, 20, 77, 46]
========================================
curr_min: 20
arr before: [0, 1, 9, 3, 5, 20, 77, 46]
for item 77
for item 46
arr after: [0, 1, 9, 3, 5, 20, 77, 46]
========================================
curr_min: 77
arr before: [0, 1, 9, 3, 5, 20, 77, 46]
for item 46
46 < 77
swap_ptr now at 7 pointing to 46
arr after: [0, 1, 9, 3, 5, 20, 46, 77]
[0, 1, 9, 3, 5, 20, 46, 77]
Result from running on option B (i.e. having option A commented out):
========================================
curr_min: 5
arr before: [5, 9, 1, 3, 0, 20, 77, 46]
for item 9
for item 1
1 < 5
swap_ptr now at 2 pointing to 1
for item 3
for item 0
0 < 1
swap_ptr now at 4 pointing to 0
for item 20
for item 77
for item 46
arr after: [0, 9, 1, 3, 5, 20, 77, 46]
========================================
curr_min: 9
arr before: [0, 9, 1, 3, 5, 20, 77, 46]
for item 1
1 < 9
swap_ptr now at 2 pointing to 1
for item 3
for item 5
for item 20
for item 77
for item 46
arr after: [0, 1, 9, 3, 5, 20, 77, 46]
========================================
curr_min: 9
arr before: [0, 1, 9, 3, 5, 20, 77, 46]
for item 3
3 < 9
swap_ptr now at 3 pointing to 3
for item 5
for item 20
for item 77
for item 46
arr after: [0, 1, 3, 9, 5, 20, 77, 46]
========================================
curr_min: 9
arr before: [0, 1, 3, 9, 5, 20, 77, 46]
for item 5
5 < 9
swap_ptr now at 4 pointing to 5
for item 20
for item 77
for item 46
arr after: [0, 1, 3, 5, 9, 20, 77, 46]
========================================
curr_min: 9
arr before: [0, 1, 3, 5, 9, 20, 77, 46]
for item 20
for item 77
for item 46
arr after: [0, 1, 3, 5, 9, 20, 77, 46]
========================================
curr_min: 20
arr before: [0, 1, 3, 5, 9, 20, 77, 46]
for item 77
for item 46
arr after: [0, 1, 3, 5, 9, 20, 77, 46]
========================================
curr_min: 77
arr before: [0, 1, 3, 5, 9, 20, 77, 46]
for item 46
46 < 77
swap_ptr now at 7 pointing to 46
arr after: [0, 1, 3, 5, 9, 20, 46, 77]
========================================
curr_min: 77
arr before: [0, 1, 3, 5, 9, 20, 46, 77]
arr after: [0, 1, 3, 5, 9, 20, 46, 77]
[0, 1, 3, 5, 9, 20, 46, 77]
Please show me how to prove my thought on this weird phenomenon. It seems when the array is passed to enumerate() in a sliced manner, it will just iterate the 'old' array from the function argument list. But when passed without any slicing, enumerate() iterates on the new array that is modified within loop. I'm not sure if I can prove this using code and documentation instead of running this experiment? Why is this design so strange? TIA.
CodePudding user response:
I can confirm it's the case. Let's see my work.
I start by creating a basic list:
foo = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Then while we iterate of the enumerate I'll edit one of the values in place:
>>> once = True
>>> for idx, val in enumerate(foo):
... if once:
... once = False
... foo[2] = 666
... print(idx, val)
...
0 0
1 1
2 666
3 3
4 4
5 5
6 6
7 7
8 8
9 9
And we notice that the enumerate shows the edited value when reaching it's index.
Now we do the same when passing a slice instead of the original:
>>> foo = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> once = True
>>> for idx, val in enumerate(foo[:]):
... if once:
... once = False
... foo[2] = 42
... print(idx, val)
...
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
>>> foo
[0, 1, 42, 3, 4, 5, 6, 7, 8, 9]
And we see that although foo
has been edited, the enumerate isn't aware of the change, since it must be using a unmodified copy of the original.
I investigated as to why that is. When using the bracket notation we are actually calling the slice class under the hood.
This says that it returns a Slice object. Which is obviously different from your original list.
You can even see the object creation in the source code if you're interested.