# Write a function to print numbers

I would like to write a python or c++ function to print numbers like the following examples (with n as input parameter):

When n = 3, print:

1 2 3
8 0 4
7 6 5

When n = 4, print:

4  5  6  7
15 0  1  8
14 3  2  9
13 12 11 10

I have an answer in the following code block, but it is not quite elegant. Does anyone have a better solution?

def print_matrix(n):
l = [i for i in range(0,n*n)]

start = (n-1)/2
end = n-1-start
count = 0
if start ==end:
l [start+ n*end] = count
start -= 1
count +=1

while start >=0:
end = n - start
for i in range(start, end-1):
x= i
y= start
print y*n +x
l[y*n +x] = count
count +=1
for i in range(start, end-1):
x = end-1
y = i
print y*n +x
l[y*n +x] = count
count +=1
for i in range(end-1,start,-1):
x= i
y= end-1
print y*n +x
l[y*n +x] = count
count +=1
for i in range(end-1, start,-1):
x = start
y = i
print y*n +x
l[y*n +x] = count
count +=1
start -=1

print l
-
Have no idea why this has been moved here. Much more suited to stack overflow. There are also many more people on SO that can help maybe you should rephrase the question. –  Loki Astari Oct 13 '12 at 14:37
@LokiAstari, its not clear to me why you think this is off-topic here. People presenting working code and ask for more elegant solutions seems to be a large part of the questions here. –  Winston Ewert Oct 13 '12 at 19:32

## migrated from stackoverflow.comOct 13 '12 at 13:39

This question came from our site for professional and enthusiast programmers.

Using a 2D array to store the matrix, we can simplify the function greatly. This uses Python 2 syntax.

def print_matrix(n):
mat = [[0]*n for _ in xrange(n)]

k = 0 # value to write
for level in reversed(xrange(n, 0, -2)):
start = n/2 - level/2
pr = pc = start # current row, column indices
if level == 1: # special case: no perimeter crawl
mat[pr][pc] = k
k += 1
continue
# walk along each edge of the perimeter
for dr, dc in [(0,1), (1,0), (0,-1), (-1,0)]:
for i in xrange(level - 1):
mat[pr][pc] = k
k, pr, pc = k+1, pr+dr, pc+dc

width = len(str(n*n-1))
for i in mat:
for j in i:
print '{:<{width}}'.format(j, width=width),
print

Samples:

>>> print_matrix(4)
4  5  6  7
15 0  1  8
14 3  2  9
13 12 11 10
>>> print_matrix(3)
1 2 3
8 0 4
7 6 5
>>> print_matrix(2)
0 1
3 2
>>> print_matrix(1)
0
>>> print_matrix(9)
49 50 51 52 53 54 55 56 57
80 25 26 27 28 29 30 31 58
79 48 9  10 11 12 13 32 59
78 47 24 1  2  3  14 33 60
77 46 23 8  0  4  15 34 61
76 45 22 7  6  5  16 35 62
75 44 21 20 19 18 17 36 63
74 43 42 41 40 39 38 37 64
73 72 71 70 69 68 67 66 65
-

The code that you and other people posted could be simplified to the following:

def slot(n, x,y):
ma = max(x,y)+1
mi = min(x,y)
o= min(n-ma,mi)
l= max(n-2*(o+1),0)
p= x+y - 2*o
if x<y: p= 4*(l+1)-p
return l*l+p

To use the code you could do:

from sys import stdout as out

n = 3
for y in xrange(n):
for x in xrange(n):
out.write(' %2d'%slot(n,x,y))
print

As you can see, it doesn't need 2D arrays.
It just calculates the values pixel-per-pixel.
It is more robust: try to do any other program with n=1000000000 and it will fail.

The results are always as expected, see them at IdeOne.

-
nice.. :) however, I'd say that min and max have their own if in their implementation, so it's around 4-5 ifs in a whole. –  Ron Klein Oct 15 '12 at 20:36
Yeah I know, but they're mathematic functions so their implementations don't count :) –  jmendeth Oct 16 '12 at 6:34

The important element of a shorter program is using a direction-array to set the step directions in your matrix; whether the matrix is represented via a 1D vector or a 2D matrix is less important. In a vector, the same-column cell in the next row is n elements away from the current cell.

def print_matrix(n):
ar = [0 for i in range(n*n)]
m, bat = n, 0
for shell in range((n+1)//2):
at = bat
m = m-2
ar[at] = val = m*m      # Each shell starts with a square
if m<0:
ar[at] = 0
break
for delta in [1, n, -1, -n]:        # Do 4 sides of shell
# Fill from corner to just before next corner
for tic in range(m+1):
ar[at] = val
at += delta             # Step to next or prev row or col
val += 1
bat += n+1                  # Step to next-inner shell

# Print matrix in n rows, n columns
for i in range(n):
for j in range(n):
print "\t", ar[i*n+j],
print

for n in range(1,7):
print "n = ", n
print_matrix(n)

This produces output like the following:

n =  1
0
n =  2
0   1
3   2
n =  3
1   2   3
8   0   4
7   6   5
...
n =  6
16  17  18  19  20  21
35  4   5   6   7   22
34  15  0   1   8   23
33  14  3   2   9   24
32  13  12  11  10  25
31  30  29  28  27  26
-

Just a direction, not a full solution, but anyway...

If limited by space, you could directly calculate each item in the matrix, given its indexes and N. So eventually you could have a function with the following signature:

def calc_mat_item(i, j, n)

The math behind this function is not that simple, but it's not that complex, too: You should calculate the shell's index, according to i, j, and n. Then you should calculate on which side of the shell are i and j ("North", "South", "East" or "West"), and calculate the "distance" (in steps) of the current item from the shell's start position.
All this is pretty much mod calculations.

Once this method is done, you could simply write a nested loop (N by N) with i and j, and print the function's value, without having to populate a matrix before that.

The calculations in the calc_mat_item should not take more than O(1) (in space and time), so eventually you could have a solution of Θ(N) in time, and O(1) in space.

Just an idea, though.

-
Yes, that's the idea I also had. Your direction has been converted into code! Checkout my answer. –  jmendeth Oct 15 '12 at 19:18
As you can see, there's only one if, everything else is maths! –  jmendeth Oct 15 '12 at 19:23