HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonModerate

Pretty-print Pascal's triangle

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
pascalprintprettytriangle

Problem

def printTrg(rows):
    r1 = [1]
    r2 = [1, 1]
    trg = [r1, r2]
    r = []
    if rows == 1:
        r1[0] = str(r1[0])
        print(' '.join(r1))
    elif rows == 2:
        for o in trg:
            for a in range(len(o)):
                o[a] = str(o[a])
            print((' ')*(2-(a+1)), (' '.join(o)))
    else:
        for i in range(2, rows):
            trg.append([1]*i)
            for n in range(1, i):
                trg[i][n] = (trg[i-1][n-1]+trg[i-1][n])
            trg[i].append(1)
        for x in range(len(trg)):
            for y in trg[x]:
                s = str(y)
                r.append(s)
            print((' ')*(rows-(x+1)), (' ' .join(r)))
            r = []


I've been learning Python for a month, and developed this program that prints out the Pascal triangle with the number of rows you want. It works fine with 5 rows.

For example, it prints:

1
    1 1
   1 2 1
  1 3 3 1
 1 4 6 4 1


But with more rows, it begins to be a little unbalanced because you have more digits on each number.

For example, a 10 row triangle:

1 
         1 1
        1 2 1
       1 3 3 1
      1 4 6 4 1
     1 5 10 10 5 1
    1 6 15 20 15 6 1
   1 7 21 35 35 21 7 1
  1 8 28 56 70 56 28 8 1
 1 9 36 84 126 126 84 36 9 1


If you could help me with the output, it would be great.

EDIT:

``
def generate_pascals_triangle(rows):
""" Returns a list of rows of a Pascal's Triangle with how many rows you want """
triangle = [[1], [1, 1]]
if rows == 1:
return triangle[0]
else:
for row_number in range(2, rows):
triangle.append([1]*row_number)
for number in range(1, row_number):
triangle[row_number][number] = (triangle[row_number-1][number-1]+triangle[row_number-1][number])
triangle[row_number].append(1)
return triangle

def difference_between_rows(row, next_row):
""" Returns the difference between two rows in the formatted way """
row_len = 0
next_

Solution

Some brief comments:

-
Your variable names are quite short (often one letter), which makes the code harder to follow. Longer and more descriptive variable names would make it easier to read and debug (e.g., trg to triangle, r1 to row1).

The input to the function printTrg is rows, but we also have variables like r, r1 and r2 which look like rows. Perhaps this would be better named as row_count?

The main style guide for Python is PEP 8, which is very readable and friendly. It gives advice on how you choose variable names, functions, and so on. In particular, for function names, it says:


Function names should be lowercase, with words separated by underscores as necessary to improve readability.

So you should rename the function printTrg to be print_trg, or even better print_triangle, to match the Python conventions.

There's also something called a docstring, which is used in Python functions to explain what the function is supposed to do.
This usually occurs in triple quotes, directly below the def line.
For example, you might write:

def printTrg(rows):
"""Prints Pascal's triangle up to the (rows)th row."""
...


There's a more detailed explanation of docstrings in PEP 257.

-
Right now the code which generates Pascal's triangle, and the code which prints it to the console, are tightly bound together.
You might be better off splitting the two into two functions:

  • generate_pascals_triangle(row_count), which would return the list of lists trg which your function already creates.



  • print_pascals_triangle(triangle), which could take the output from generate and print it to the console.



-
The elif rows == 2 block is redundant, as the else block does exactly the same thing. The range(2, rows) never executes if rows is 2.

While we're in the else block, I’m unclear why your range goes to rows in the first for loop, but to len(trg) in the second. Unless I've confused myself, these are always the same thing. And later in the same loop, you use rows to count the number of spaces you need.

-
The way you generate the next row of Pascal's triangle (insert a list of 1s, update the entries, then put an extra 1 on the end) could be simplified. Since you’re making a list for the entries in that row, you could use a list comprehension. (If you're not familiar with these, then there are lots of good explanations on Google.)

Here's a simple example of a function which takes the previous row of Pascal's triangle, works out which row you're in now (by looking at the length of the previous row), then generates the new row with a list comprehension:

def next_row(row):
"""Returns the next row of Pascal's triangle."""
n = len(row)
new_row = [row[0]] + [row[i] + row[i+1] for i in range(n - 1)] + [row[-1]]
return new_row


We're still doing essentially the same thing, but this looks cleaner, and we've split up some more of the logic. This can make life easier when it comes to debugging.

This also works if we give it the first row [1], so we don't need to consider the cases rows == 1 and rows != 1 separately when we generate Pascal's triangle. Again, we're able to simplify some of the code.

-
As you’ve pointed out, things get out of line if you print a large number of rows, as two and three digit numbers come in to play. If you split this into two functions, then you can play around with the printing without affecting the arithmetic (which works perfectly).

So with all that in mind, here's how I might rewrite your code.
First I have the function which I mentioned above, which takes one row of Pascal's triangle and returns the next:

def next_row(row):
"""Returns the next row of Pascal's triangle."""
n = len(row)
new_row = [row[0]] + [row[i] + row[i+1] for i in range(n - 1)] + [row[-1]]
return new_row


Next, we have a function which just generates the entries of Pascal's triangle. Since we're not printing anything (that will come later), and the arithmetic for generating new rows is in another function, this is much shorter than before:

def generate_pascals_triangle(row_count):
"""Returns the entries of Pascal's triangle."""
row1 = [1]
triangle = [row1]
for i in range(1, row_count):
triangle.append(next_row(triangle[-1]))
return triangle


If we wanted, we could supply the first entry (or even a whole first row) as an argument. You could see what happens if you make 2 the top entry, or started several levels deep. This is left for you to play with. (You may find this explanation of optional and named arguments useful.)

Finally, we come to the printing problem. We can use the logic from your else block, almost unmodified (just with more descriptive variable names):

`def print_pascals_triangle(triangle):
"""Prints the entries of Pascal's triangle."""
for row_no in range(len(triangle)):
row = triangle[row_no]
printed_row = []
for entry in row:

Code Snippets

$ python pascal-triangle.py

Context

StackExchange Code Review Q#43223, answer score: 19

Revisions (0)

No revisions yet.