How to understand the Python code I wrote for a problem - python

If I give 2 output is
2 2 2
2 1 2
2 2 2
and for 3 is
3 3 3 3 3
3 2 2 2 3
3 2 1 2 3
3 2 2 2 3
3 3 3 3 3
The code is as follows:
def square(arr, val):
if val is 1:
return [[1]] //self understandable
n = val + (val - 1) //getting array size, for 2 its 3
sideAdd = [val] * n
arr.insert(0, sideAdd) //for 2 it add [2,2,2] at first
arr.append(sideAdd) //append [2,2,2]
for i in range(1, n-1): //for inner elements add val to either sides
arr[i].insert(0, val) // like, for 2 [val,1,val]
arr[i].append(val)
return(arr)
array = square([[2, 2, 2], [2, 1, 2], [2, 2, 2]], 3)
# print(array)
for i in array:
print(*i)
The output goes like:
3 3 3 3 3
3 2 2 2 3
3 2 1 2 3
3 2 2 2 3
3 3 3 3 3
which is a correct answer.
But when I tried to complete the whole solution by giving values through for loop and sending returned array as parameter again through the same function like
n = 3
arr = []
for i in range(1, n+1):
arr = square(arr, i)
the whole code is
def square(arrx, val):
if val is 1:
return [[1]]
n1 = val + (val - 1)
sideAdd = [val] * n1
arrx.insert(0, sideAdd)
arrx.append(sideAdd)
for i in range(1, n1-1):
arrx[i].insert(0, val)
arrx[i].append(val)
return arrx
n = 3
arr = []
for i in range(1, n+1):
arr = square(arr, i)
for i in arr:
print(*i)
This returns the answer as:
3 3 3 3 3
3 3 2 2 2 3 3
3 2 1 2 3
3 3 2 2 2 3 3
3 3 3 3 3
which is wrong
I already tried running in debug mode in pycharm, there I got an unusual thing. Check the screenshot below. When j = 1 (index), the code inserts 2 in blue underline but also in red which should not because the red underline index is 3 (insertion of 2 should occur at j = 3), and when j = 3 again insertion at index 1 (j = 1) is happening which makes the output 3 3 2 2 2 3 3 instead of 3 2 2 2 3.
I can't understand how that's happening. The screenshot is as follows:
https://imgur.com/yce47Pi

I think you are making this more complicated than it needs to be. You can determine the correct value of any cell from their indexes alone. Given a size n and row/column [i,j], the value is:
max(abs(n - 1 - j) + 1, abs(n - 1 - i) + 1)
For example:
def square(n):
arr = []
for i in range(n + n-1):
cur = []
arr.append(cur)
for j in range(n + n -1):
cur.append(max(abs(n - 1 - j) + 1, abs(n - 1 - i) + 1))
return arr
Then
> square(3)
[[3, 3, 3, 3, 3],
[3, 2, 2, 2, 3],
[3, 2, 1, 2, 3],
[3, 2, 2, 2, 3],
[3, 3, 3, 3, 3]]
> square(5)
[[5, 5, 5, 5, 5, 5, 5, 5, 5],
[5, 4, 4, 4, 4, 4, 4, 4, 5],
[5, 4, 3, 3, 3, 3, 3, 4, 5],
[5, 4, 3, 2, 2, 2, 3, 4, 5],
[5, 4, 3, 2, 1, 2, 3, 4, 5],
[5, 4, 3, 2, 2, 2, 3, 4, 5],
[5, 4, 3, 3, 3, 3, 3, 4, 5],
[5, 4, 4, 4, 4, 4, 4, 4, 5],
[5, 5, 5, 5, 5, 5, 5, 5, 5]]
Edit
The problem with current code is this:
sideAdd = [val] * n
arr.insert(0, sideAdd)
arr.append(sideAdd)
You adding a reference to the same array (sideAdd) twice. So later when you add columns with:
arrx[i].insert(0, val)
arrx[i].append(val)
these two array are the same if they were added in an earlier loop. Adding to the first array also adds one to the second and adding to the second adds to the first. So you end up doing it twice. There are a couple ways to fix that, but the easiest is adding a copy the second time:
sideAdd = [val] * n
arr.insert(0, sideAdd)
arr.append(sideAdd[:]) # Make a copy — don't add the same reference

We can make use of numpys broadcasting rules here:
>>> np.maximum(np.abs(np.arange(-2, 3)[:, None]), np.abs(np.arange(-2, 3))) + 1
array([[3, 3, 3, 3, 3],
[3, 2, 2, 2, 3],
[3, 2, 1, 2, 3],
[3, 2, 2, 2, 3],
[3, 3, 3, 3, 3]])
So we can render the cube with:
import numpy as np
def cube(n):
ran = np.abs(np.arange(-n+1, n))
cub = np.maximum(ran[:, None], ran) + 1
return '\n'.join(' '.join(map(str, row)) for row in cub)
For example:
>>> print(cube(1))
1
>>> print(cube(2))
2 2 2
2 1 2
2 2 2
>>> print(cube(3))
3 3 3 3 3
3 2 2 2 3
3 2 1 2 3
3 2 2 2 3
3 3 3 3 3
>>> print(cube(4))
4 4 4 4 4 4 4
4 3 3 3 3 3 4
4 3 2 2 2 3 4
4 3 2 1 2 3 4
4 3 2 2 2 3 4
4 3 3 3 3 3 4
4 4 4 4 4 4 4
>>> print(cube(5))
5 5 5 5 5 5 5 5 5
5 4 4 4 4 4 4 4 5
5 4 3 3 3 3 3 4 5
5 4 3 2 2 2 3 4 5
5 4 3 2 1 2 3 4 5
5 4 3 2 2 2 3 4 5
5 4 3 3 3 3 3 4 5
5 4 4 4 4 4 4 4 5
5 5 5 5 5 5 5 5 5

Related

What will be the best approach for a digit like pattern in python?

i was trying a pattern in Python
if n == 6
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
after trying to think a lot
i did it like this --->
n = 6
for i in range(1,n):
x = 1
countj = 0
for j in range(i,n):
countj +=1
print(j,end=" ")
if j == n-1 and countj < n-1 :
while countj < n-1:
print(x , end =" ")
countj +=1
x +=1
print()
but i don't think it is the best approach, I was trying to search some better approach , but not able to get the proper one, So that I came here,, is there any possible better approach for the problem?
I would do like this, using a rotating deque instance:
>>> from collections import deque
>>> n = 6
>>> d = deque(range(1, n))
>>> for _ in range(1, n):
... print(*d)
... d.rotate(-1)
...
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
There is a similar/shorter code possible just using range slicing, but maybe it's a bit harder to understand how it works:
>>> ns = range(1, 6)
>>> for i in ns:
... print(*ns[i-1:], *ns[:i-1])
...
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
You could also create a mathematical function of the coordinates, which might look something like this:
>>> for row in range(5):
... for col in range(5):
... print((row + col) % 5 + 1, end=" ")
... print()
...
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
A too-clever way using list comprehension:
>>> r = range(5)
>>> [[1 + r[i - j - 1] for i in r] for j in reversed(r)]
[[1, 2, 3, 4, 5],
[2, 3, 4, 5, 1],
[3, 4, 5, 1, 2],
[4, 5, 1, 2, 3],
[5, 1, 2, 3, 4]]
more-itertools has this function:
>>> from more_itertools import circular_shifts
>>> circular_shifts(range(1, 6))
[(1, 2, 3, 4, 5),
(2, 3, 4, 5, 1),
(3, 4, 5, 1, 2),
(4, 5, 1, 2, 3),
(5, 1, 2, 3, 4)]
You can use itertools.cycle to make the sequence generated from range repeat itself, and then use itertools.islice to slice the sequence according to the iteration count:
from itertools import cycle, islice
n = 6
for i in range(n - 1):
print(*islice(cycle(range(1, n)), i, i + n - 1))
This outputs:
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
Your 'pattern' is actually known as a Hankel matrix, commonly used in linear algebra.
So there's a scipy function for creating them.
from scipy.linalg import hankel
hankel([1, 2, 3, 4, 5], [5, 1, 2, 3, 4])
or
from scipy.linalg import hankel
import numpy as np
def my_hankel(n):
x = np.arange(1, n)
return hankel(x, np.roll(x, 1))
print(my_hankel(6))
Output:
[[1 2 3 4 5]
[2 3 4 5 1]
[3 4 5 1 2]
[4 5 1 2 3]
[5 1 2 3 4]]
Seeing lots of answers involving Python libraries. If you want a simple way to do it, here it is.
n = 5
arr = [[1 + (start + i) % n for i in range(n)] for start in range(n)]
arr_str = "\n".join(" ".join(str(cell) for cell in row) for row in arr)
print(arr_str)

How to format tabular data WITHOUT row labels?

For instance right now the output is:
Temp [C] v [m3/kg] u [kJ/kg] s [kJ/kgK]
Temp [C] 1 2 1 3
v [m3/kg] 0 1 0 3
u [kJ/kg] 2 4 2 3
s [kJ/kgK] 2 4 2 3
and I want it to look like:
Temp [C] v [m3/kg] u [kJ/kg] s [kJ/kgK]
1 2 1 3
0 1 0 3
2 4 2 3
2 4 2 3
Here is the code I am currently using:
units = ['Temp [C]', 'v [m3/kg]', 'u [kJ/kg]', 's [kJ/kgK]']
data = ([1, 2, 1, 3], [0, 1, 0, 3], [2, 4, 2,3], [2, 4, 2,3])
format_row = "{:>12}" * (len(units) + 1)
print(format_row.format("", *units))
for unit, row in zip(units, data):
print(format_row.format(unit, *row))
units = ['Temp [C]', 'v [m3/kg]', 'u [kJ/kg]', 's [kJ/kgK]']
data = ([1, 2, 1, 3], [0, 1, 0, 3], [2, 4, 2,3], [2, 4, 2,3])
fmt_string = '{:<15}' * len(units)
print(fmt_string.format(*units))
for row in data:
print(fmt_string.format(*row))
Prints:
Temp [C] v [m3/kg] u [kJ/kg] s [kJ/kgK]
1 2 1 3
0 1 0 3
2 4 2 3
2 4 2 3

Python create a sequence of non repeating numbers

I want to create a sequence something like this [[1,2],[3,4],[5,6],..].
Here is what I tried and got:
n = 3 # I need three lists
for i in range(0,n+1,1):
print(i+1,i+2)
1 2
2 3
3 4
4 5
Expected output:
1 2
3 4
5 6
n = 3
pairs = [list([i, i + 1]) for i in range (1, 2 * n, 2)]
for pair in pairs:
for x in pair:
print(x, end = ' ')
print()
This prints:
1 2
3 4
5 6
And the list pairs so formed is:
[[1, 2], [3, 4], [5, 6]]
Take step of 2 and end at n*2
n=3
output = []
for i in range(0,n*2,2):
print(i+1,i+2)
output.append([i+1,i+2])
print(output)
1 2
3 4
5 6
[[1, 2], [3, 4], [5, 6]]
After a trial, I found the following answer:
for i in range(0,n,1):
print(2*i+1,2*i+2)

An efficient way to concatenate rows of a 2-dim array according to a given list of pairs of indexes

Suppose I have a 2 dimensional array with a very large number of rows, and a list of pairs of indexes of that array. I want to create a new 2 dim array, whose rows are concatenations of the rows of the original array, made according to the list of pairs of indexes. For example:
a =
1 2 3
4 5 6
7 8 9
0 0 0
indexes = [[0,0], [0,1], [2,3]]
the returned array should be:
1 2 3 1 2 3
1 2 3 4 5 6
7 8 9 0 0 0
Obviously I can iterate the list of indexes, but my question is whether there is a more efficient way of doing this. I should say that the list of indexes is also very large.
First convert indexes to a Numpy array:
ind = np.array(indexes)
Then generate your result as:
result = np.concatenate([a[ind[:,0]], a[ind[:,1]]], axis=1)
The result is:
array([[1, 2, 3, 1, 2, 3],
[1, 2, 3, 4, 5, 6],
[7, 8, 9, 0, 0, 0]])
Another possible formula (with the same result):
result = np.concatenate([ a[ind[:,i]] for i in range(ind.shape[1]) ], axis=1)
You can do this in one line using NumPy as:
a = np.arange(12).reshape(4, 3)
print(a)
b = [[0, 0], [1, 1], [2, 3]]
b = np.array(b)
print(b)
c = a[b.reshape(-1)].reshape(-1, a.shape[1]*b.shape[1])
print(c)
'''
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
[[0 0]
[1 1]
[2 3]]
[[ 0 1 2 0 1 2]
[ 3 4 5 3 4 5]
[ 6 7 8 9 10 11]]
'''
You can use horizontal stacking np.hstack:
c = np.array(indexes)
np.hstack((a[c[:,0]],a[c[:,1]]))
output:
[[1 2 3 1 2 3]
[1 2 3 4 5 6]
[7 8 9 0 0 0]]

the code does not give the results what I want using equal sign in python

I do have a code like this.
import numpy as np
a = np.zeros(shape = (4,4))
a+= 2
b = np.zeros(shape = (4,4))
b+=2
t = 0
while t<2:
for i in range(1,3):
for j in range(1,3):
if a[i,j] == a[i-1,j]:
b[i,j] = a[i,j]+1
print(a,t)
print(b,t)
a = b
t+= 1
I am hoping that at t = 2
a = [2 2 2 2, 2 3 3 2, 2 3 3 2, 2 2 2 2] and b = [2 2 2 2, 2 3 3 2, 2 4 4 2, 2 2 2 2]
but in fact at the end of the run the a = [2 2 2 2, 2 3 3 2, 2 4 4 2, 2 2 2 2]
anyone know why? is it because i am declaring a = b? if it is yes, is there any way to do it?
thanks..
Replace a=b (which makes a and b the same array) with a[:,:]=b (which copies the elements of b into a).

Categories