3
\$\begingroup\$

I have written alphabet rangoli code in python and would like to get it reviewed. The goal is to print concentric diamond shapes made of letters, with "a" at the center, "b" forming the next layer, then "c", etc.

Any comments on making it more logical or concise shall be appreciated.

import math


# input the size of alphabet rang oli
def print_rangoli(size):
    totalHeight = (2 * size) - 1
    totalWidth = (2 * totalHeight) - 1
    numberOfAlphabets = 1
    numberOfDashes = (totalWidth - numberOfAlphabets) // 2
    # initialize a list of alphabets
    alphabets = "a b c d e f g h i j k l m n o p q r s t u v w x y z".split(" ")
    # run a for loop totalHeight number of times
    for i in range(1, totalHeight + 1):
        if i <= math.ceil(totalHeight / 2):
            print("-" * numberOfDashes, end="")
            listIndex = size - 1
            for k in range(math.ceil(numberOfAlphabets / 2)):
                if size == 1:
                    print(alphabets[listIndex])
                else:
                    print(alphabets[listIndex] + "-", end="")
                listIndex -= 1
            listIndex += 1
            for k in range(math.floor(numberOfAlphabets / 2)):
                listIndex += 1
                if i == math.ceil(totalHeight / 2) and k == math.floor(numberOfAlphabets / 2) - 1:
                    print(alphabets[listIndex], end="")
                else:
                    print(alphabets[listIndex] + "-", end="")

            print("-" * (numberOfDashes - 1))
            if i != math.ceil(totalHeight / 2):
                numberOfAlphabets += 2
                numberOfDashes -= 2
        else:
            numberOfDashes += 2
            numberOfAlphabets -= 2
            print("-" * numberOfDashes, end="")
            listIndex = size - 1
            for k in range(math.ceil(numberOfAlphabets / 2)):
                print(alphabets[listIndex] + "-", end="")
                listIndex -= 1
            listIndex += 1
            for k in range(math.floor(numberOfAlphabets / 2)):
                listIndex += 1
                print(alphabets[listIndex] + "-", end="")

            print("-" * (numberOfDashes - 1))


if __name__ == "__main__":
    size = int(input())
    print_rangoli(size)

\$\endgroup\$
3
  • 2
    \$\begingroup\$ What is alphabet rangoli, please? I can infer that it's some pattern, but an explanation can't hurt. This raises on n > 26, which probably should be handled. \$\endgroup\$
    – ggorlen
    May 5, 2022 at 16:53
  • \$\begingroup\$ I would love to see example output here \$\endgroup\$ May 6, 2022 at 23:46
  • \$\begingroup\$ Just a comment on the variable name alphabets, numberOfAlphabets, etc. This should be letters and numberOfLetters. In English, "A" is a letter, "B" is a letter and A,B, and C are 3 letters. There is only one alphabet, ABCDEFGHIJKLMNOPQRSTUVWXYZ. \$\endgroup\$ May 6, 2022 at 23:49

2 Answers 2

5
\$\begingroup\$

You can simplify the code by a lot.


The first simple change is that you don't need to define the alphabet this way:

alphabets = "a b c d e f g h i j k l m n o p q r s t u v w x y z".split(" ")

Your code would work just fine if you treat a string as indexable:

alphabets = "abcdefghijklmnopqrstuvwxyz"

Simplifying further, you can take advantage of the builtin module:

from string import ascii_lowercase as alphabets

Instead of tediously figuring out where to put the "-" characters as left padding, right padding, and internally, you can use str.center(width, '-') to do the padding, and '-'.join('cbabc') to obtain "c-b-a-b-c". Putting those two techniques together, then, you could write

print('-'.join('cbabc').center(11, '-'))

… to obtain

--c-b-a-b-c--

You don't need to do so much arithmetic to calculate numberOfDashes and numberOfAlphabets. I'd just compose the middle row as a string, then call len(…) to have Python tell you how wide the layout has to be.


The way you've structured your code, you have four cases: if i <= math.ceil(totalHeight / 2): to test whether you are in the top half or the bottom half, and for each of those cases, a for k in … loop to handle the left side, and another for k in … loop to handle the right.

Instead of all that, I suggest using the abs() function to help you do a symmetric iteration.


Suggested solution

from string import ascii_lowercase

def seq(n, i):
    return '-'.join(
        ascii_lowercase[i + abs(j)]
        for j in range(i - n, n - i + 1)
    )

def rangoli(n):
    width = len(seq(n, 0))        # Pad everything to match the width of the center row
    return '\n'.join(
        seq(n, abs(i)).center(width, '-')
        for i in range(-n, n + 1)
    )

if __name__ == "__main__":
    size = int(input())
    print(rangoli(size - 1))
\$\endgroup\$
0
\$\begingroup\$

In order to print all rows you could use two cycles:

  • an increasing cycle to print the first half rows
  • a decreasing cycle to print the second half rows

In order to print a single row, you can notice that:

  • the content has letters concatenated to their own reverse, with exception of the middle one (e.g. edcb + a + bcde)
  • each space is printed as a hyphen
  • each letter/space is separated by a hyphen

Given this situation, what you can do is first generate the content (letters+spaces) and then use Python join operation to generate your rangoli row:

# input the size of alphabet rang oli
def print_rangoli(size):
    alphabet = "abcdefghijklmnopqrstuvwxyz"
    
    # extracting letters to use from alphabet
    letters = alphabet[:size]

    # variables used in the cycles
    dashes  = ''
    content = ''

    # generating first half
    for i in range(1, size+1, 1):
        dashes  = '-'*(size-i)
        content = letters[:i][::-1] + letters[1:i]
        print('-'.join(dashes + content + dashes))

    # generating second half
    for i in range(size-1, 0, -1):
        dashes  = '-'*(size-i)
        content = letters[:i][::-1] + letters[1:i]
        print('-'.join(dashes + content + dashes))

if __name__ == "__main__":
    size = int(input())
    print_rangoli(size)

This solution also handles borderline cases related to the size range domain [0,26]. If you want to handle cases related to size < 0 or size > 26, you can do that with some checks at the beginning of the function.

\$\endgroup\$
0

Your Answer

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

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