C# Number Triangle Pattern (Left-Shifted)

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

What Is This Pattern?

A left-shifted descending number triangle prints digits i..rows on each row, so every line starts one digit higher and the left edge appears to slide right.

Remember
Rule: for i = 1..n, print i..n

12345
2345
345
45
5       ← 5 rows

In C# the outer loop picks the row start i, the inner loop prints j from i to rows, then Console.WriteLine() moves to the next line. Compare with Program 1, which prints 1..i while counting the outer loop down.

How to Solve It

Two ways to emit the same shape — start with nested loops, then optionally shorten with LINQ.

MethodIdeaBest for
Nested loopsOuter = start 1..n, inner = digits i..n via WriteLearning, interviews, exams
Enumerable.RangeBuild a whole digit row in one callShorter demos once loops click

Pseudocode

Pseudocode
for i from 1 to rows:
    for j from i to rows:
        print j (no newline)
    print newline

Cheat sheet

GoalPattern
Pick row startfor (i = 1; i <= rows; i++)
Print digits i..rowsfor (j = i; j <= rows; j++) Console.Write(j);
End the rowConsole.WriteLine();
One-line row shortcutConsole.WriteLine(string.Join("", Enumerable.Range(i, rows - i + 1)));
Program 1 shape insteadfor (i = rows; i >= 1; i--) with j = 1..i

Write vs WriteLine

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

Live Preview

Change the row count and the left-shifted 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
12345
2345
345
45
5

Worked Walkthrough — rows = 4

Trace each outer-loop value of i and the digits the inner loop prints.

iInner jPrinted rowDigits
11..412344
22..42343
33..4342
44..441

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

C# Programs

Three complete programs: fixed height, row-count input, and a LINQ shortcut. Use View Output for sample results.

Example 1 — Fixed rows = 5

Outer loop picks the start digit; inner loop prints from i through rows.

C#
using System;

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

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

How It Works

1. Pick the start. for (i = 1; i <= rows; i++) yields 1, 2, 3, 4, 5 as row starts.

2. Print digits. When i = 1, the inner loop prints 12345; when i = 5, just 5.

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

Example 2 — User Input

Read the row count at runtime. Prefer int.TryParse in real apps so bad input does not throw.

C#
using System;

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

            Console.Write("Enter the number of 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++)
            {
                for (j = i; j <= rows; j++)
                {
                    Console.Write(j);
                }
                Console.WriteLine();
            }
        }
    }
}

How It Works

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

2. Same nested loops. Four rows start at 1234 and end at 4.

Example 3 — LINQ Shortcut

Build each row with Enumerable.Range, then print it in one call.

C#
using System;
using System.Linq;

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

            for (int i = 1; i <= rows; i++)
            {
                Console.WriteLine(string.Join("", Enumerable.Range(i, rows - i + 1)));
            }
        }
    }
}

How It Works

1. Build digits. Enumerable.Range(i, rows - i + 1) yields i..rows; string.Join concatenates them.

2. Same shape. Identical output to Example 1 — keep the two-loop version for exams that ask for both bounds. Add using System.Linq;.

Edge Cases & Pitfalls

Check these before calling the solution done.

wrong start

j = 1 instead of j = i

That prints 1..rows every row (a rectangle). Keep for (j = i; j <= rows; j++).

WriteLine early

WriteLine(j) inside the inner loop

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

off-by-one

j < rows instead of j <= rows

You drop the last digit on every row (e.g. 12345 becomes 1234).

rows = 1

Single 1

Output is just 1 — a good sanity check.

rows ≤ 0

Empty output

The outer loop never runs. Validate and prompt again for clearer UX.

Bad input

Convert.ToInt32 throws

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

Time and Space Complexity

ProgramTimeExtra space
Nested loops (Examples 1–2)O(n²)O(1)
LINQ shortcut (Example 3)O(n²)O(n) per row for the joined string

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

Key Takeaways

  • Rule: for i = 1..n, print digits i..n with Write.
  • Start at i: the inner loop begins at j = i, which is what creates the left shift.
  • Write vs WriteLine: digits stay on the line; WriteLine advances after each row.
  • Next step: Program 3 reverses the digit order on each row.

One line: for each start from 1 to n, print i..n with Write, then WriteLine.

Frequently Asked Questions

The inner loop starts at j = i, not j = 1. When i increases (1, 2, 3, …), each row begins at that value and prints until rows.
Because each next row starts at a higher i, numbers below i are not printed anymore — the triangle shifts left visually.
Console.Write stays on the same line. Console.WriteLine ends the current line. Digits use Write; the row break uses WriteLine after the inner loop.
Program 1 counts the outer loop down and prints 1..i. Program 2 counts up and prints i..rows — same total prints, different shape.
Change the rows variable or read it from the console. The outer loop runs from 1 to rows, and the inner loop prints j from i to rows.
Yes. Console.WriteLine(string.Join("", Enumerable.Range(i, rows - i + 1))) prints one row. Nested loops are better for learning.
O(n²) for n rows because total prints are n+(n-1)+…+1 = n(n+1)/2.
Prefer int.TryParse(Console.ReadLine(), out rows) so bad input does not throw FormatException.
The outer loop never runs, so nothing is printed. Validate and prompt again if you want a clear user message.

Did you know?

Each row starts at i and prints through rows, so the left edge shifts right each line — still O(n²) total prints for n rows.

Next: Reverse Descending Number Triangle

Keep a shrinking width, but print digits in reverse order on each row.

Program 3 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