Related
I am writing a program that involves me to create a matrix 'B' edited from another matrix 'A'. Both the matrix have the same size and I simply want that for every position where matrix 'A' contains a 1, matrix 'B' also contains a 1 in that position. For example:
if __name__ == '__main__':
mat_A = [[0, 0, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 0, 0]]
R = len(mat_A)
C = len(mat_A[1])
mat_B = [[0]*C]*R #Initialise matrix B to be the same size as A
for i in range (R):
for j in range (C):
if mat_A[i][j] == 1:
mat_B[i][j] = 1
print(mat_B)
However, in this case, it prints me an output like such:
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
Process finished with exit code 0
This tells me that the code is finding an instance where mat_A[i][j] = 1 and then changing the entire mat_B together. Shouldn't it only affect the specific position in 'B' rather than all?
Thank you for your help.
p.s. The above is only a very simple example I wrote to try and debug. There are multiple complex steps in the if loop.
The line
mat_B = [[0]*C]*R
creates a list of length R where each element is the same list consisting of zeros. If you change one of the sublists of mat_B, you change them all, since they are all the same list. You can fix this, for example, as follows:
mat_B = [[0]*C for i in range(R)]
After that, your code should work fine.
As a side note, it is easier to accomplish such operations using numpy arrays:
import numpy as np
mat_A = np.array([[1, 2, 3], [0, 1, 7], [3, 1, 0], [0, 1, 0], [0, 2, 4]])
mat_B = np.zeros_like(mat_A)
mat_B[mat_A == 1] = 1
I have a Python ndarray that is Boolean and has this shape: (32, 1600, 1600). Each layer (I visualize the 1600x1600 as a layer and the 32 as 32 layers), from 1-32, has a varying number of True and the Trues might be located at different index in its respective 2D layer. I want to "flatten" (don't know if that's the right term) this from 32 to 1, so that the resulting array is (1600, 1600) with every True carrying over to its corresponding place in the result. This is a very simplified example of my starting multidimensional array. The array is Boolean, with True/False, but I used 0 for False and 1 for True in this example:
array([[[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0], #two "Trues"
[0, 1, 0, 1, 0], #two "Trues"
[0, 1, 0, 0, 0], #one "True"
[0, 0, 0, 0, 0]],
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0], #two "Trues"
[0, 1, 0, 1, 0], #two "Trues"
[0, 0, 0, 0, 0]]])
I want the final array to look like this. Every True location is carried over to its corresponding place in the new array. Since it's Boolean, it shouldn't be cumulative.
array([[[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0], #two "Trues"
[0, 1, 0, 1, 0], #two "Trues"
[0, 1, 0, 1, 0], #two "Trues"
[0, 0, 0, 0, 0]]])
Since you have an array of booleans, let's create one.
a = np.array([[[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 0, 0]],
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 1, 0],
[0, 0, 0, 0, 0]]], dtype=bool)
You want to perform the or operation along the first axis. To do this, you can simply take the sum along the zeroth axis, and find if the elements are greater than zero.
a.sum(axis=0) > 0
gives:
array([[False, False, False, False, False],
[False, True, False, True, False],
[False, True, False, True, False],
[False, True, False, True, False],
[False, False, False, False, False]])
To convert it to an integer array, simply multiply this by 1:
1 * (a.sum(axis=0) > 0)
gives:
array([[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 1, 0],
[0, 0, 0, 0, 0]])
You could try this:
import numpy as np
arr = np.array([[[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 0, 0]],
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 1, 0],
[0, 0, 0, 0, 0]]], dtype=bool)
result = 1*np.logical_or.reduce(arr, axis=0)
I believe this is what you're looking for, and I think it should be easy enough to convert this back to True / False as you described. If you need any help please comment.
arr = [[[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 0, 0]],
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 1, 0],
[0, 0, 0, 0, 0]]]
new_arr = [ [ 1 if arr[0][i][j] == 1 or arr[1][i][j] == 1 else 0 for j in range(len(arr[0][0])) ] for i in range(len(arr[0])) ]
print(new_arr)
Output:
[[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 1, 0],
[0, 0, 0, 0, 0]]
I am working with 3D arrays, for example, in an IPython console:
In [8]: xx = [[[0 for i in range(4)] for j in range(4)] for k in range(4)]
xx
Out[9]:
[[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]]
print(xx)
[[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]]
When I just evaluate the array in the console it is nicely formatted, but when I print() it, it formats in one long line which then wraps and looks horrible. There are long-winded ways to reproduce the terminal-style formatting from within a program, but is it possible to just call the function that formats for the console directly? I tried
repr(xx)
But that does not have the desired effect. Such a function could be generally useful, not just for arrays.
Use pprint, like the below:
>>> import pprint
>>> pprint.pprint(xx)
[[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]]
>>>
I have a project where I am trying to edit portions of nested lists.
Say I started with this list:
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]]
I want to iterate over a portion of this list so that I get an output that is a square of ones in the center like so.
[[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0]]
I tried using a for-loop to iterate through the list and a nested for loop to iterate through the sub-lists. However, that did not work. What I got instead was this list:
[[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0]]
Here is my code:
list = [[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]]
for i in range(1,4):
for j in range(1,4):
list[i][j] = 1
Why won't this code work? I have searched for a day or two and have not found an answer. Thank you in advance to whoever takes the time to answer or comment.
The code you posted is working fine:
>>> list = [[0, 0, 0, 0, 0],
... [0, 0, 0, 0, 0],
... [0, 0, 0, 0, 0],
... [0, 0, 0, 0, 0],
... [0, 0, 0, 0, 0]]
>>>
>>> for i in range(1,4):
... for j in range(1,4):
... list[i][j] = 1
...
>>> pprint(list)
[[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0]]
Check that your code actually looks like what you posted here.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
“Least Astonishment” in Python: The Mutable Default Argument
I'm trying to create a list of objects from the class "fooclass", with different attributes, but always end up with all elements of the list containing the same values.
Here is the code I run:
#!/usr/bin/env python
class fooclass():
def __init__(self,vertices = [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]]):
self.vertices = vertices
l=[]
print(l)
a=fooclass(); a.vertices[0]=[7,9,9]; l.append(a)
print 'a=', a.vertices
a=fooclass(); a.vertices[0]=[789,9,9]; l.append(a)
print 'a=', a.vertices
print(l[0].vertices)
print(l[1].vertices)
print(l)
l=[]
print(l)
a=fooclass(); a.vertices[0]=[7,9,9]; l.append(a)
print 'a=', a.vertices
b=fooclass(); b.vertices[0]=[789,9,9]; l.append(b)
print 'b=', b.vertices
print(l[0].vertices)
print(l[1].vertices)
print(l[0])
print(l[1])
And the output I get:
$ python ./class_test2.py
[]
a= [[7, 9, 9], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
a= [[789, 9, 9], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[789, 9, 9], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[789, 9, 9], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
[<__main__.fooclass instance at 0x7f945eafecf8>, <__main__.fooclass instance at 0x7f945eafed88>]
[]
a= [[7, 9, 9], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
b= [[789, 9, 9], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[789, 9, 9], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[789, 9, 9], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
<__main__.fooclass instance at 0x7f945eafecf8>
<__main__.fooclass instance at 0x7f945eafed88>
Why are l[0].vertices and l[1].vertices exactly the same despite inputting different values?
System info:
Ubuntu 10.04.4 LTS
$ python --version
Python 2.6.5
$ uname -a
Linux *** 2.6.32-39-generic #86-Ubuntu SMP Mon Feb 13 21:50:08 UTC 2012 x86_64 GNU/Linux
Note: Tried with Python 3.1.2 (just changing the print statements), same problem. :(
The default value of vertices can be modified in Python. You can rewrite __init__ like so to avoid it:
def __init__(self, vertices=None):
if vertices is None:
vertices = [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]]
self.vertices = vertices
When you set the default argument vertices = [...], you're actually instantiating a single list object to be used every time the argument is unspecified. That means both of your fooclass instances are sharing--and modifying--a single list.
Instead, instantiate it inside your __init__ method if no value is given for that argument. That ensures that a new one is created each time the method is run.
Edit: phihag's answer gives good example code for correcting __init__.