1

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()

3 Answers 3

2

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))

Sign up to request clarification or add additional context in comments.

Comments

1

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 ;)

Comments

0
  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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.