Mathematics
Mathematics

Reputation: 113

Printing given pattern using for loop

enter image description here

I have written the following code and it runs but I am using 4 for loops and I would like to know if there is more effective way to write this code.

n = int(input('Please Enter the highest number \n'))
col = 2*n-1
for i in range(1, n+1):
  for j in range(1, col+1):
    if j >= i and j <= col-i+1:
      print(n-i+1, end=' ')
    elif j < i:
      print(n+1-j, end=' ')
    else:
      print(j+1-n, end=' ')
print()

for i in range(n-1, 0, -1):
  for j in range(1, col+1):
    if j >= i and j <= col - i + 1:
      print(n-i+1, end=' ')
    elif j < i:
      print(n + 1 - j, end=' ')
    else:
      print(j + 1 - n, end=' ')
print()

Upvotes: 1

Views: 677

Answers (3)

F. Gyllenhammar
F. Gyllenhammar

Reputation: 341

You could find the position relative to the center (di, dj), and then use its largest component as the label for that cell:

n = int(input('Please Enter the highest number \n'))
col = 2 * n
for i in range(1, col):
    row = []
    for j in range(1, col):
        di, dj = abs(n-i), abs(n-j)
        row.append(max(di,dj) + 1)
    print(' '.join(str(x) for x in row))

Upvotes: 2

Doug
Doug

Reputation: 31

Problem Definition

Breaking this down into a few logical obsevations.

  1. We have a grid of numbers that appears symmetrical.
  2. However, the middle row / middle column are only repeated once, this is important.
  3. Therefore it is more similar to looking down on a pyramid from above, where 1 represents the highest point, and 4 / n the lowest.

So we know that to follow DRY principle, we only need to generate one corner of the pyramid, and then we simply copy it to the other 3 corners.

Solution

(assuming use of pure python 3.x only, without libraries such as numpy)

def print_pyramid(n=4):
    """Print a symmetrical pyramid of numbers descending from n"""

    # Calculate bottom half of grid
    bottom = []
    for j in range(n):
        row = [max(i, j + 1) for i in range(1, n + 1)]
        row = row[::-1][:-1] + row
        bottom.append(row)

    # Invert bottom to get top
    rows = bottom[::-1][:-1] + bottom

    # Print formatted
    for row in rows:
        row_str = [str(i) for i in row]
        print(f"{' '.join(row_str)}")


print_pyramid(4)

This is definitely not the most efficient method (see recursive functions), but it is fairly quick and pythonic.

Explanation

Bottom Right corner

First we generate an array of numbers, 1 => n:

[i for i in range(1, n + 1)]

[1, 2, 3, 4]

Then we loop n times to generate this for each row (j), but replace any values lower than j using max:

for j in range(n):
    row = [max(i, j+1) for i in range(1,n+1)]

[1, 2, 3, 4]
[2, 2, 3, 4]
[3, 3, 3, 4]
[4, 4, 4, 4]

Bottom Left Corner (~mirror image)

First we select the row elements in reverse with slice notation [::-1]
Then we remove the last element [:-1]

row = [max(i, j+1) for i in range(1,n+1)]
row[::-1][:-1]

[4, 3, 2]
[4, 3, 2]
[4, 3, 3]
[4, 4, 4]

Top Half Now we create the top half using the same slicing technique to reverse and select from our existing nested array.

bottom[::-1][:-1]

[4, 4, 4, 4, 4, 4, 4]
[4, 3, 3, 3, 3, 3, 4]
[4, 3, 2, 2, 2, 3, 4]

Finally, we print our full array with string formatting

for row in rows:
    row_str = [str(i) for i in row]
    print(f"{' '.join(row_str)}")

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

P.S. Please don't cheat on your homework assignments ;)

Upvotes: 1

mportes
mportes

Reputation: 1837

  1. Since the inner loops are identical, you could join the two outer loops into one, e.g. by chaining the two ranges:
from itertools import chain

...

for i in chain(range(1, n + 1), range(n - 1, 0, -1)):

    ...
  1. The condition can be simplified like this:
i <= j <= col - i + 1

Upvotes: 0

Related Questions