3
\$\begingroup\$

I have solved the pascal's triangle problem. I am not good at writing efficient programs, hence any suggestions/ comments shall be welcomed.

# pascal's triangle through list
heightOfTriangle = int(input())             # input height of triangle
powerOf2 = 0                                # setting the initial power of 2 to be zero
lstOfCoefficients = [1, 1]                  # initializing a list containing only starting and ending 1
# running a main loop height of triangle number of times
for i in range(heightOfTriangle):
    # printing the starting spaces
    print(" " * (heightOfTriangle - i), end="")
    # nested for loop for editing the list of coefficients
    if (i - 1) > 0:
        lst = lstOfCoefficients[::]
        for k in range(i - 1):
            lstOfCoefficients.insert(k + 1, lst[k] + lst[k + 1])
        lstOfCoefficients = lstOfCoefficients[0 : i] + lstOfCoefficients[(len(lstOfCoefficients) - 1): len(lstOfCoefficients)]
    # running a nested for loop to print digits
    # run nested for loop i + 1 times
    for j in range(i + 1):
        print(lstOfCoefficients[j], end=" ")
    print()

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

PEP 8

The Style Guide for Python Code has many recommendations that all Python programs should follow. These include:

  • snake_case for variable and function names, instead of bumpyWords. As such, heightOfTriangle should be height_of_triangle, or perhaps less verbose triangle_height
  • no spaces in list slices. lstOfCoefficients[0 : i] should be lstOfCoefficients[0:i]

Unused variables

powerOf2 is unused, and can be safely removed.

Logical thoughts should be grouped

You have print(" " * (heightOfTriangle - i), end="") to print several blanks at the start of an output line. Then, you have 8 lines of code where calculations are done for the row coefficients. Then, you continue with the printing.

Your code would be more understandable if you did all your printing in one spot. The indentation print statement could sit just above for j ...

Use functions

Using function helps separate your code into logical blocks. Here, you have user input and program output all mashed together. If the Pascal triangle printing code was in its own function, you could call it after getting the user input. The function would logically contain its own variables, like the height of the triangle, but since we'd be inside a "Pascal's triangle" function, you could just name it height for brevity without loss of clarity.

Efficiency

After you generate 1 5 10 10 5 1, the row is computed by adding 1+5, 5+10, 10+10, 10+5, and 5+1, inserting these at the appropriate positions. This gives you:

[1, 6, 15, 20, 15, 6, 5, 10, 10, 5, 1]

What is all that "fluff" doing at the end of the list? That exists because you are inserting the values into the previous row, making the row about twice as long as the previous row. You then trim off all the fluff with ...

lstOfCoefficients[0 : i]

and then you are ...

+ lstOfCoefficients[(len(lstOfCoefficients) - 1): len(lstOfCoefficients)]

... which is a very verbose way of add a list of just the last element. You can state this much simpler using negative indexing like lstOfCoefficients[-1:]. Of course, we know the last element is always a one, so you could also simply use + [1].

Instead of inserting, causing the list to double in length, you could simply overwrite the previous values, and then simply append the final 1.

        for k in range(i - 1):
            lstOfCoefficients[k + 1] = lst[k] + lst[k + 1]
        lstOfCoefficients.append(1)

Reworked code

def print_pascals_triangle(height):
    coefficients = [1]
    for row_num in range(height):
        print(" " * (height - row_num), *coefficients)

        # Compute next row
        previous = coefficients[:]
        for k in range(row_num):
            coefficients[k + 1] = previous[k] + previous[k + 1]
        coefficients.append(1)

print_pascals_triangle(int(input()))

Note: print(*coeff) is like saying print(coeff[0], coeff[1], coeff[2], ...) with all the elements of the list exploded out as separate arguments. Since Python prints out the arguments separated by spaces by default, the printing is done in a single statement.

\$\endgroup\$
1
\$\begingroup\$

Use functions. You have a review with some useful advice, and its best advice is that you organize your programs around functions. Here I'll extend that idea.

Functions should be focused. If we take a full program and just stick it inside a function, we have improved the situation a little bit, but not by very much. One of the main advantages of using functions is that it allows you to decompose something complex (an entire program) into parts that are hopefully much simpler. Your current code gets the job done and is generally reasonable, but I would not describe it as intuitive: it forces the reader to keep track of several variables, which are modified as the logic proceeds. In the middle of those algorithmic manipulations, the code also concerns itself with matters of presentation (printing and alignment).

A simpler approach: a function to compute one row. It's easy to describe the algorithm to compute the values for a single row: get the previous row and add up adjacent values, and then stick some ones on each end. Three things worth noting about the function below: (1) it is focused on a very narrow task; (2) it is data-oriented (it takes data and returns data) rather than side-effect-oriented (eg, printing); and (3) functools.cache is used to memoize the function to avoid recomputation of already-computed rows (data-orientation makes that possible).

from functools import cache

@cache
def pascal_row(n):
    if n < 1:
        return []
    elif n == 1:
        return [1]
    else:
        prev = pascal_row(n - 1)
        return [1] + [a + b for a, b in zip(prev, prev[1:])] + [1]

Computing the whole triangle. To compute all of the data, just invoke the row function multiple times.

def pascals_triangle(height):
    return [pascal_row(n) for n in range(1, height + 1)]

Printing the triangle is a separate concern. Our pascals_triangle() function just returns a list-of-lists. To make it look like a triangle, we need to decide how much we care about the aesthetics. I care very little, so I'll just join the numbers together with spaces. But you might care more than I do, in which case you are free to copy my data-generating functions but write a fancier version of the triangle-printing function (for example, you could get the width of the last rows_str and then print r.center(width), or you could put in even more effort to get the numbers to align perfectly). In any case, that's another benefit of functions: by decomposing your program into small parts, it's easier to make changes without having to dig into the details of everything.

import sys

def main(args):
    height = int(args[0]) if args else 6
    rows = pascals_triangle(height)
    rows_str = [' '.join(map(str, r)) for r in rows]
    for r in rows_str:
        print(r)

if __name__ == '__main__':
    main(sys.argv[1:])
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.