1
\$\begingroup\$

I have to write a program in python that will take a number and print a right triangle attempting to use all numbers from 1 to that number. For example:

Enter number: 10
Output:
7 8 9 10
4 5 6
2 3
1

Enter number: 6
Output:
4 5 6
2 3
1

Enter number: 20
Output:
11 12 13 14 15
7 8 9 10
4 5 6
2 3
1

For which I have written the following function

def print_right_triangle(num):
    c = 1
    k = 0
    l = []
    while(k < num-1):
        v = []
        for i in range(c):
            v.append(k+1)
            k += 1
        c += 1
        if k > num:
            break
        l.append(v)

    p = len(l)
    for i in range(p):
        for j in l[p-(i+1)]:
            print(j, end=' ')
        print()
    return None

print_right_triangle(10)

It's giving the same output and solved my problem. I was wondering is there any more pythonic way to do this

\$\endgroup\$
5
  • 2
    \$\begingroup\$ One liner with a bit of maths to find x(x+1)/2 = n: lambda x: [print(*range(1+i*~-i//2, 1+i*-~i//2)) for i in range(int(((1+8*x)**.5-1)/2), 0, -1)] \$\endgroup\$
    – rak1507
    Nov 19 at 11:43
  • \$\begingroup\$ @rak1507 Thank you so much!!! \$\endgroup\$
    – coderina
    Nov 19 at 13:27
  • \$\begingroup\$ @rak1507 could you please explain 1+i*~-i//2 this, its so tricky to understand this \$\endgroup\$
    – coderina
    Nov 19 at 14:14
  • 1
    \$\begingroup\$ ~-i is magic for (i-1) so it's 1 + i * (i-1) // 2 (sorry: code golfing habits die hard) \$\endgroup\$
    – rak1507
    Nov 19 at 14:38
  • \$\begingroup\$ @rak1507 ohhokay....got it..thank you so much for responding! \$\endgroup\$
    – coderina
    Nov 19 at 18:54
3
\$\begingroup\$

Optimized != pythonic

Optimized means "spending less resources". "Pythonic" means "using idiomatic Python features". Sometimes they come together, sometimes don't. Pythonic code is clean and maintainable, while optimized can be very unclear and need many comments.

Anyway, optimization should start with making the code readable, and pythonic code should be readable.

Make more use of Python features

List comprehensions, range arguments and unpacking can be very handy. This code

    v = []
    for i in range(c):
        v.append(k+1)
        k += 1

is clearly just a

    v = [k+1+i for i in range(c)]
    k += c

and, changing the range arguments,

    v = list(range(k+1, k+c))
    k += c

And this code

    for j in l[p-(i+1)]:
        print(j, end=' ')
    print()

can be written as

    print(*l[p-(i+1)])

and

p = len(l)
for i in range(p):
    print(*l[p-(i+1)])

is walking the l list backwards, so it's

for line in reversed(l):
    print(*line)

This is pythonic.

Optimizations

Change the algorithm. Here you're gathering all the number in a list to output them. But the numbers are all in order, so you can easily avoid lists at all - just make loops with prints.

First, read some theory.

Now you know that only numbers that equal n*(n+1)/2 can be used to build such triangles. You can solve n*(n+1)/2 = num as a quadratic equation and round n down to get the number of lines without loops like rak1507 did.

Next, find formulas for starting and ending numbers in each line to put them into range arguments.

And now you can code it in three lines.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you so much!! for this wonderful explaination \$\endgroup\$
    – coderina
    Nov 19 at 13:27

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.