C# Number Triangle Pattern (Bidirectional)

Beginner
6 min read
Updated: Sep 2026
3 programs
Live preview

What Is This Pattern?

A bidirectional number triangle prints a shrinking row of the same digit, where the digit rises on early rows then mirrors back down on the last rows.

Remember
Rule: shrink j = i..n; digit = i or n+1-i

11111
2222
333
22
1       ← 5 rows

In C# the outer loop picks the row, the inner loop prints one digit repeatedly from i to rows, and an if/else (or ternary) chooses i vs rows + 1 - i. Then Console.WriteLine() ends each row.

How to Solve It

One nested-loop idea with two useful variants — packed digits and spaced digits.

MethodIdeaBest for
Shrink + map digitInner j = i..rows; digit is i then rows + 1 - iLearning, interviews, exams
Spaced digitsSame logic; print val + " "Practice variants

Pseudocode

Pseudocode
for i from 1 to rows:
    if i < rows - 1:
        val = i
    else:
        val = rows + 1 - i
    for j from i to rows:
        print val (no newline)
    print newline

Cheat sheet

GoalPattern
Walk each rowfor (i = 1; i <= rows; i++)
Shrink the lengthfor (j = i; j <= rows; j++)
Pick the digitval = (i < rows - 1) ? i : (rows + 1 - i);
Repeat the digitConsole.Write(val);
End the rowConsole.WriteLine();

Write vs WriteLine

APIEffectUse for
Console.WriteStays on the same lineEach repeated digit val
Console.WriteLineEnds the current lineAfter the inner loop

Live Preview

Change the row count and the bidirectional triangle updates instantly — including the total digit count.

Whole numbers from 1 to 9 (keeps digits single-width). Tap a chip or type a value — the preview redraws as you go.

Live result 5 rows · 15 digits
11111
2222
333
22
1

Worked Walkthrough — rows = 5

Trace each outer-loop value of i, the mapped digit, and how many times it prints.

iDigit valTimes (j = i..5)Printed row
11 (i < 4)511111
2242222
333333
42 (6 - i)222
5111

Total digits are 5+4+3+2+1 = 15 — the triangular number n(n+1)/2.

C# Programs

Three complete programs: fixed height, generalized row count, and spaced digits. Use View Output for sample results.

Example 1 — Fixed rows = 5

Shrink each row; map the digit with if (i < 4) else 6 - i.

C#
using System;

namespace MyApp
{
    class Program
    {
        static void Main(string[] args)
        {
            int i, j;

            for (i = 1; i <= 5; i++)
            {
                for (j = i; j <= 5; j++)
                {
                    if (i < 4)
                        Console.Write(i);
                    else
                        Console.Write(6 - i);
                }
                Console.WriteLine();
            }
        }
    }
}

How It Works

1. Shrink the length. for (j = i; j <= 5; j++) prints 5, 4, 3, 2, then 1 digits.

2. Map the digit. Early rows use i (1, 2, 3); later rows use 6 - i (2, 1).

3. Newline. WriteLine() after the inner loop starts the next shorter row.

Example 2 — User Input

Generalize the mapping with rows. Prefer int.TryParse so bad input does not throw.

C#
using System;

namespace MyApp
{
    class Program
    {
        static void Main(string[] args)
        {
            int rows;
            int i, j, val;

            Console.Write("Enter rows: ");
            if (!int.TryParse(Console.ReadLine(), out rows) || rows < 1)
            {
                Console.WriteLine("Please enter a positive whole number.");
                return;
            }

            for (i = 1; i <= rows; i++)
            {
                val = (i < rows - 1) ? i : (rows + 1 - i);

                for (j = i; j <= rows; j++)
                {
                    Console.Write(val);
                }
                Console.WriteLine();
            }
        }
    }
}

How It Works

1. Validate rows. TryParse rejects non-numeric input; require rows >= 1.

2. Compute val once. Set the digit before the inner loop, then just Write(val) repeatedly.

Example 3 — Spaced Digits

Same mapping and shrink — only the print statement adds a space.

C#
using System;

namespace MyApp
{
    class Program
    {
        static void Main(string[] args)
        {
            int rows = 5;
            int i, j, val;

            for (i = 1; i <= rows; i++)
            {
                val = (i < rows - 1) ? i : (rows + 1 - i);

                for (j = i; j <= rows; j++)
                {
                    Console.Write(val + " ");
                }
                Console.WriteLine();
            }
        }
    }
}

How It Works

1. Same digit map. val still rises then mirrors down.

2. Add gaps. Write(val + " ") inserts spaces between repeated digits.

Edge Cases & Pitfalls

Check these before calling the solution done.

hard-coded 4

i < 4 for other sizes

For general rows, use i < rows - 1 and rows + 1 - i (Example 2).

wrong start

j = 1 instead of j = i

That prints a full-width rectangle. Keep for (j = i; j <= rows; j++).

WriteLine early

WriteLine(val) inside the inner loop

That puts each digit on its own line. Use Write(val); call WriteLine() only after the row finishes.

rows = 1

Single 1

Output is just 1 — a good sanity check.

rows = 2

Both rows mirror

With rows - 1 = 1, both rows use the mirror formula — output is 11 then 1.

Bad input

Convert.ToInt32 throws

Prefer int.TryParse so non-numeric input does not crash the program.

Time and Space Complexity

ProgramTimeExtra space
Packed digits (Examples 1–2)O(n²)O(1)
Spaced digits (Example 3)O(n²)O(1)

There are n rows printing n+(n-1)+…+1 digits, so total work is n(n+1)/2.

Key Takeaways

  • Rule: shrink with j = i..rows; digit is i then rows + 1 - i.
  • Map once: compute val before the inner loop, then just repeat it.
  • Write vs WriteLine: digits stay on the line; WriteLine advances after each row.
  • Next step: Program 26 mixes descending numbers with a diagonal asterisk.

One line: for each row, pick a rising-then-mirroring digit and print it rows - i + 1 times.

Frequently Asked Questions

For i = 5, the condition i < rows - 1 is false, so the program prints rows + 1 - i which becomes 1.
Because the inner loop runs from j = i to rows. As i increases, the inner loop executes fewer times.
Digits rise (1, 2, 3) on early rows then mirror down (2, 1) on the last rows via the rows + 1 - i mapping.
Console.Write repeats the digit on the same line. Console.WriteLine ends the row after the inner loop finishes.
A single inner loop with a digit mapping keeps the shrinking row logic in one place.
Replace hard-coded 5 with rows and use val = (i < rows - 1) ? i : (rows + 1 - i) — see Example 2.
O(n²) for n rows because total prints are triangular (n + (n-1) + … + 1).
Prefer int.TryParse(Console.ReadLine(), out rows) so bad input does not throw FormatException.
Only one row prints — a single 1.

Did you know?

This pattern prints repeated digits per row. The inner loop runs from j = i to rows, shrinking each row. The row digit is i for the first half, then switches to rows + 1 - i to produce 22 and 1.

Next: Descending Numbers with Diagonal Asterisk

Print descending digits and place a star on the diagonal of each row.

Program 26 tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

12 people found this page helpful