Difference between including or not including [:] - python-3.x

Both declarations produce the same results but I want to know what the difference is behind the scenes.
a = [1,2,3,4,5]
a[:] = a[0:3]
print(a)
a = [1,2,3,4,5]
a = a[0:3]
print(a)

This can be better explained with another variable.
Let's say that a and b are the same. When we use slice assignment, both a and b get changed because they are the same list. Without assigning it to the slice of a means making a new list that is called a that has no relation to b anymore.
a = b = [0, 1, 2]
a[:] = a[0:2]
# a and b point to the same object and that got changed
print(a) # gives [0, 1]
print(b) # gives [0, 1]
a = b = [0, 1, 2]
a = a[0:2]
# a and b point to two different objects sharing no memory together
print(a) # gives [0, 1]
print(b) # gives [0, 1, 2]

Related

matrix addition giving wrong answer

I am from java background, I am learning python matrix operation. I have an assignment question to add two matrices manually I can't figure out the error in my logic. need help thank you
x = [[12,7,3],[4 ,5,6],[7 ,8,9]]
y = [[5,8,1],[6,7,3],[4,5,9]]
row = len(x)
col = len(x[0])
ans = [[0] * col] * row
for i in range(len(x)):
for j in range(len(x[i])):
ans[i][j] = x[i][j] + y[i][j]
print()
print(ans)
output :
[[11, 13, 18], [11, 13, 18], [11, 13, 18]]
The problem is here:
ans = [[0]*col]*row
This statement creates row number of objects, where each object is [[0]*col]. What this means is that, each "sub-list" in the list is pointing to the same list.
(More information about this behaviour here: List of lists changes reflected across sublists unexpectedly)
You can verify that by checking the id values of ans[0],ans[1] and so on:
>>> a = [[0]*col]*row
>>>
>>> a
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> id(a[0])
140336190913992
>>> id(a[1])
140336190913992
>>> id(a[2])
140336190913992
This means, if we set a[0][1] = 10 (say), then EACH sub-list will have the the value 10 set. This is because all the lists point to the same list.
i.e.
>>> a[0][1] = 10
>>> a
[[0, 10, 0], [0, 10, 0], [0, 10, 0]]
Now, how do we avoid this?
You can do so by initiliasing the ans list in a different way, as in:
b = [[0 for x in range(col)] for y in range(row)]
You can verify that all the sub-lists point to different addresses by using id again:
>>> id(b[0])
140336190512520
>>> id(b[1])
140336190765000
>>> id(b[2])
140336197031816
So now if you run your original program, you will get desired results.
TLDR; your modified program looks like this:
x = [[12,7,3],[4 ,5,6],[7 ,8,9]]
y = [[5,8,1],[6,7,3],[4,5,9]]
row = len(x)
col = len(x[0])
ans = [[0 for x in range(col)] for y in range(row)]
for i in range(len(x)):
for j in range(len(x[i])):
ans[i][j] = x[i][j] + y[i][j]
print(ans)

How to get the index of an numpy.ndarray

I would to print the images on index i but I get an error of only integer scalar arrays can be converted to a scalar index. How can I convert I to int for each iteration
I have tried replacing images[i] with images[n] it worked but not the result I want.
c = [1 1 1 0 1 2 2 3 4 1 3]
#c here is list of cluster labels obtained after Affinity propagation
num_clusters = len(set(c))
images = os.listdir(DIR_NAME)
for n in range(num_clusters):
print("\n --- Images from cluster #%d ---" % n)
for i in np.argwhere(c == n):
if i != -1:
print("Image %s" % images[i])
I expect the output to be the name of the image, but I instead get TypeError: only integer scalar arrays can be converted to a scalar index that is because i is of type numpy.ndarray
Look at the doc of np.argwhere, it does not return a list of integers, but a list of lists
x = array([[0, 1, 2], [3, 4, 5]])
np.argwhere(x>1)
>>> array([[0, 2], [1, 0], [1, 1], [1, 2]])
y = np.array([0, 1, 2, 3, 4, 6, 7])
np.argwhere(y>3)
>>> array([[4], [5], [6]])
so without knowing what your c looks like, I assume your i will be of the form np.array([[3]]) instead of an integer, and therefore your code fails. Print i for testing and extract (e.g. i[0][0] and a test that it is non-empty) the desired index first before you do i != -1.
Meta
It is best practise to post a minimal reconstructable example, i.e. other people should be able to copy-paste the code and run it. Moreover, if you post at least a couple lines of the traceback (instead of just the error), we would be able to tell where exactly the error is happening.

Issue with appending to an array

I cannot understand why the piece of code described below does what it does
import numpy as np
N = 2
A=[];
B=[];
for i in range(N):
B.append(i)
A.append(B)
The first time the for loop runs (for i =0), A = [[0]]. The second time the loop runs (for i =1), B = [0,1] and so I expect A = [[0],[0,1]], since we are appending B to A. However, when I print A, I get A = [[0,1],[0,1]]. Why do I not get the form I expect?
A and B here are pointing to objects in memory. So, if the object itself is modified in memory, all variables pointing to that object will show the updated value.
Now let's look at the code:
B.append(i) -> list B is appended with value of i.
A.append(B) -> list A is appended with reference of B. But the object itself referenced by B is getting modified in each iteration, and hence the most updated value of B is shown as each element of A at each level of iteration. If you run the loop for more iterations and print A, you'll notice this behavior clearly.
One way of overcoming this issue is appending A with a copy of B.
N = 4
A=[]
B=[]
for i in range(N):
B.append(i)
A.append(B.copy())
print(A)
# Output:
# [[0]]
# [[0], [0, 1]]
# [[0], [0, 1], [0, 1, 2]]
# [[0], [0, 1], [0, 1, 2], [0, 1, 2, 3]]

What is the difference between two types of list additions in python?

I'm adding the list with itself in 2 ways. In output the memory location of updated list sometimes matches with parent list and sometimes not.
May I know the explanation of this?
In 1st case I checked with + operator and assigned result to list reference.
But in second case I used += operator.
1st case:
x=[1,2,3]
print(x, id(x))
x+=x
print(x, id(x))
output:
[1, 2, 3] 88777032
[1, 2, 3, 1, 2, 3] 88777032
2nd case:
y=[1,2,3]
print(y, id(y))
y=y+y
print(y, id(y))
output:
[1, 2, 3] 88297352
[1, 2, 3, 1, 2, 3] 88776904
1st case:
x += x just extends existing x by adding x
2nd case:
y = y+y creates a new list by concatenating y two times (y and y) and then assigns the result to newly created object y

Unusual function behavior - returns different results for same variable?

I have a list as part of a game I'm working on. Let's say:
my_list = [1, 2, 3, 4, 5]
I also have a function:
def my_function(my_list):
a = [x for x in my_list if x < 4]
b = [x for x in my_list if x < 4] ## exactly the same as for `a`
print(a)
print(b)
The result of calling my_function(my_list) is:
a prints as it should:
[1, 2, 3]
But b prints an empty list:
[]
Obviously the code above is just an example (it would be highly impractical for me to copy my whole code), but it's pretty much a copy of the issue I'm facing in my code. Does anyone know what could be causing such behavior?

Resources