Printing star greater symbol in Java

Posted on

Problem

I need to print this in Java, but I feel that my code is too big:

*
**
***
****
***
**
*
public static void main(String[] args) {

    for(int i=0; i<=3; i++) {
        for(int j=0; j<=i; j++) {
            System.out.print("*");
        }
        System.out.println();
    }

    for(int j=1; j<=3; j++) {
        for(int i=3; i>=j; i--) {
            System.out.print("*");
        }
        System.out.println();
    }
}

Solution

Here is a lovely way to do it using only one nested for-loop:

for (int i = 0; i < 7; i++) {
    for (int numStars = 0; numStars < 4 - Math.abs(3 - i); numStars++) {
        System.out.print("*");
    }
    System.out.println();
}

This uses the Math.abs function to perform the calculation of how many stars to print.

If we take a look at a plot of the classic Math.abs we can see that it looks useful. We need to flip it upside-down though, this is done by taking 4 - abs(x) which would look like this. Finally, we need to switch it to the right a bit, so we modify the input to the function call and end up with this: 4 – abs(3 – x)

Images courtesy of wolframalpha.com

4-abs(x)

enter image description here

4-abs(3 – x)

enter image description here

Finally, here is a very flexible solution, which also works with even numbers:

int rows = 20;
double maximumValue = Math.ceil(rows / 2.0);
double shifted = maximumValue - 1;
for (int i = 0; i < rows; i++) {
    int count = (int) (maximumValue - Math.abs(shifted - i));
    if (i >= rows / 2 && rows % 2 == 0) // slight fix for even number of rows
        count++;
    
    for (int numStars = 0; numStars < count; numStars++) {
        System.out.print("*");
    }
    System.out.println();
}

This will output:

*
**
***
****
*****
******
*******
********
*********
**********
**********
*********
********
*******
******
*****
****
***
**
*

You’ve hard-coded 3 in three places. Yet, the output contains a row with four stars. That’s underhanded programming. The culprit is this line:

for(int j=0; j<=i; j++)

Idiomatic Java would be either

for (int j = 0; j < somelimit; j++)

or

for (int j = 1; j <= somelimit; j++)

I also find the way that you interchanged i and j between the first and second halves of the program disconcerting.


Surely you should define a function that accepts a parameter. What varies? The fill character? The size? Otherwise, the simplest solution would be

public static void main(String[] args) {
    System.out.println("*n**n***n****n***n**n*");
}

I am in favour of keeping two for-loops, one increasing and one decreasing. Combining those into one loop would likely make it difficult to see the intent at a glance. As for how you generate each line of n stars, though, it’s not particularly interesting how you accomplish it. I’ve chosen a one-line hack for the solution below, but you may wish to pick a more traditional approach.

private static String repeat(String s, int n) {
    // A bit of a hack, and not very efficient.  Feel free to reimplement.
    return String.format("%" + n + "s", "").replaceAll(" ", s);
}

public static void printArrow(String fill, int width, PrintStream out) {
    for (int i = 1; i < width; i++) {
        out.println(repeat(fill, i));
    }
    for (int i = width; i >= 1; i--) {
        out.println(repeat(fill, i));
    }
}

public static void main(String[] args) {
    printArrow("*", 4, System.out);
}

You don’t need a loop for this.

public static void main(String[] args) {
        String ln = System.getProperty("line.separator");
        System.out.println("*" + ln
                        +  "**" + ln
                        +  "***" + ln
                        +  "****" + ln
                        +  "***" + ln
                        +  "**" + ln
                        +  "*");
}

Using multiple print("*") calls for each star is very inefficient. Print is a slow command, and it also makes what is a relatively simple process (printing a line of stars) become a more complicated loop.

A more efficient way to output the triangle would be to use one println per line. An even better way would be for one println for the whole puzzle, but that has a potential issue of the n value is large.

A real trick here would be to build up one String value for the longest line, and then just print substrings for the shorter ones.

Note, using Math.abs(...) is a clever way to manipulate the substring, but combining it with a loop from negative width to positive width makes it even easier to understand.

Additionally, putting the code in to its own method, instead of the main method, makes the code more reusable.

public static final void triangle(int width) {
    String longest = buildLine(width, '*');

    for (int i = -width + 1; i < width; i++) {
        System.out.println(longest.substring(Math.abs(i)));
    }
}

private static String buildLine(int width, char c) {
    char[] chars = new char[width];
    Arrays.fill(chars, c);
    return new String(chars);
}

public static void main(String[] args) {
    triangle(5);
}

Leave a Reply

Your email address will not be published. Required fields are marked *