Trouble understanding this simple code

# number of rows
rows = 5
k = 2 * rows - 2
for i in range(0, rows):
    # process each column
    for j in range(0, k):
        # print space in pyramid
        print(end=" ")
    k = k - 2
    for j in range(0, i + 1):
        # display star
        print("* ", end="")
    print("")

This code produces the mirror “*” triangle pattern. I can work out the first line but in the second line isn’t k iterated down to the value of 0? When i is now 1 for the second line, isn’t the second for loop for j in range (0,0)?

As you’ve observed, this prints a pyramid by printing enough spaces to
indent the first asterisk, then the appropriate number of asterisks.
Because the asterisks are separated by spaces, the indent reduces by 2
each row.

So the outer loop prints enough rows.

There are 2 inner loops. The first prints the indent, printing a single
space k times. The second inner loop prints the asterisks, which
prints i+1 asterisks.

When i=1 on the second iteration, i+1 == 2 and thus 2 asterisks get
printed.

Some random notes:

  • you can write range(0,n) as just range(n); it will still count
    from 0 through n-1 inclusively i.e. n values
  • if I were writing a single space, I’d probably use print(" ",end="")
    much like the asterisk print() lower down, rather than printing
    “nothing” and padding it with end=" "

Cheers,
Cameron Simpson cs@cskk.id.au

Yes, k is reduced to 0. range(0,00 is an empty sequence; no problem. Lets think about what we are doing and more directly translate to python.

Each row has rows chars separated (and joined) by spaces. The rows chars are split into rows-i spaces and i stars, where i ranges from 1 to rows. The following does this succinctly, using string multiplication and join.

rows = 5
for stars in range(1, rows+1):
    print(' '.join(' '*(rows - stars) + '*'*stars))

I often find it helpful to calculate entire lines before printing.

Thank you! So for the first line k is iterated down by two from 8 until that loop (0,k) becomes (0,0) and the asterisk loop starts and prints one asterisk, I understand that. Then on the second line it starts over with the first for loop (0,rows) now being i=1 and the second for loop (0,k) still being (0,0) no? I mean the value of k is still 0 from the previous line isn’t it? I get that it now iterates three spaces on the second line but I don’t see how k is reset since the line k=2*rows-2 is before all the loops.

Thanks!
Dave

You wrote:

So for the first line k is iterated down by two from 8 until that loop
(0,k) becomes (0,0) and the asterisk loop starts and prints one
asterisk, I understand that. Then on the second line it starts over
with the first for loop (0,rows) now being i=1 and the second for loop
(0,k) still being (0,0) no? I mean the value of k is still 0 from the
previous line isn’t it? I get that it now iterates three spaces on the
second line but I don’t see how k is reset since the line k=2*rows-2 is
before all the loops.

I think you’re misunderstanding how the loops work, the meaning of the
nesting and exactly when things get computed. I’m going to recite the
code against below then talk about it in more detail:

 # number of rows
 rows = 5
 k = 2 * rows - 2
 for i in range(0, rows):
     # process each column
     for j in range(0, k):
         # print space in pyramid
         print(end=" ")
     k = k - 2
     for j in range(0, i + 1):
         # display star
         print("* ", end="")
     print("")

What we’ve got here is 3 loops, one outer loop and two inside it.

When you commence the outer loop:

 for i in range(0, rows):

the expression range(0, rows) is computed once at this point, returing
a “range” object which counts from 0 through to 5 (excluding the
5, so 0 to 4 inclusive). We could fiddle with the value in rows
later and not affect how many times this loop runs, because the “range”
object/counter has already been made.

So this makes a loop setting i to a value of 0 for the first pass,
1 for the next pass and so on.

Every time that loop runs, it runs everything inside it once.

The second loop:

 for j in range(0, k):
     # print space in pyramid
     print(end=" ")

Again, this constructs a “range” object which counts from 0 through to
k-1, for the current value if k when the loop is started. On the
first pass of the outer loop k=8 so this counts from 0 through to
7 inclusive, and prints 8 spaces as a result.

Then we finish the loop, we reduce k by 2. This is the only line
which changes k.

     k = k - 2

k is now 6. Not 0.

I think that’s the source of your confusion. The for j loop does not
change k
.

Try making another Python file which this changed code:

 # number of rows
 rows = 5
 k = 2 * rows - 2
 print("rows =", rows, "k =", k)
 for i in range(0, rows):
     print("  outer loop top: i =", i, "k =", k)
     # process each column
     for j in range(0, k):
         print("    first inner loop: j =", j, "i =", i, "k =", k)
     k = k - 2
     for j in range(0, i + 1):
         print("    second inner loop: j =", j, "i =", i, "k =", k)
 print("DONE, i =", i, "k =", k)

You should see what happens to the variables on each pass more clearly.

Cheers,
Cameron Simpson cs@cskk.id.au

Thanks so much for this. For some reason I was thinking that the value of k iterated to zero as that loop (0,k) cycled through when its j that is iterating, I was confusing j with k… Thanks again!

1 Like