-1

So I am trying to delete elements from an array and do some calculations with this array. The thing is, I want to still keep a copy of the original array, so I made a new array and assigned it the values of the original array. The thing is, whenever I print out the length of the original and the new array, it gives me the same length, but it gives me the length of the new array. How do I make a new array with the same values as 'a', but without changing 'a'

a = [2, 4, 5, 7, 8, 9]
b = []    
b = a    
for _ in range(2):
    m = min(b)
    b[:] = (x for x in b if x != m)

print(len(b))
print(len(a))
Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
  • 1
    You are not copying - you are aliasing . You give a second name to the same array (which is a list btw). try `b = a[:]` this will copy it - only works if the lists content is immutable. if your list contains other lists it will "copy" the reference to that list but not the nested lists contents - that would be a deepcopy(). search SO for python + list + deep copy – Patrick Artner Dec 28 '17 at 22:46
  • When you do `b=a`, `b` is not the empty array `b=[]` anymore, but it _becomes_ `a` (kind of) So any removal in `a` will be reflected in `b` and viceversa. – Savir Dec 28 '17 at 22:47
  • Possible duplicate of [How to clone or copy a list?](https://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list) – Patrick Artner Dec 28 '17 at 22:51
  • You can look at this [example with output](https://stackoverflow.com/a/47969887/7505395) regarding shallow copy effects with inner lists – Patrick Artner Dec 28 '17 at 22:53
  • Your numbers are conveniently ordered - to remove the lowest 2 you could simply use `b=a[2:]` - if not ordered yet and order is not important you could use `c=sorted(b)[2:]` – Patrick Artner Dec 28 '17 at 23:00

3 Answers3

4

Saying b = a just creates a new variable that references the existing list object. To make a copy of a list you could use the list() function or list slicing:

b = list(a)
b = a[:]

That said, to create a new list from an existing one filtering out some elements you could use a list comprehension:

from heapq import nsmallest
m = nsmallest(2, a)
b = [x for x in a if x not in m]
Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
1

There is difference between list and list[:].
When reading, list is a reference to the original list, and list[:] shallow-copies the list.

When assigning, list (re)binds the name and list[:] slice-assigns, replacing what was previously in the list.

However, if the list elements are lists themselves, even list1 = list[:] has its problems. Consider:

>>> a = [[1,2,3],[4,5,6],[7,8,9]]
>>> b = a[:]
>>> b[0].remove(2)
>>> b 
[[1, 3], [4, 5, 6], [7, 8, 9]]
>>> a
[[1, 3], [4, 5, 6], [7, 8, 9]]

This happens because each list element being copied to b is a list itself, and this copying of lists involves the same problem that occurs with the normal list1 = list2. The shortest way out is to explicitly copy every list element this way:

>>> a = [[1,2,3],[4,5,6],[7,8,9]]
>>> b=[[j for j in i] for i in a]   
>>> b
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> b[0].remove(2)
>>> b
[[1, 3], [4, 5, 6], [7, 8, 9]]
>>> a
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Arash Hatami
  • 5,297
  • 5
  • 39
  • 59
1

You are not copying - you are aliasing . You give a second name to the same array (which is a list btw). try b = a[:] this will copy it - only works if the lists content is immutable.

If your list contains other lists it will "copy" the reference to that list but not the nested lists contents - that would be a deepcopy().

If you want to remove the lowest 2 you could also resort to sorting and slicing (you list is already sorted so no sort needed)

a = [2, 4, 5, 7, 8, 9] 

b = a[2:] // slice, ignore first 2 entries which are the lowest 2 

c = sorted(a)[2:] // implicitly creates a new sorted list, ignore lowest 2

print(b)
print(c)

Output:

[5, 7, 8, 9]
[5, 7, 8, 9]
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69