A descending number triangle prints digits 1..i on each row, with the outer loop counting down so the first row is longest.
Remember
Rule: for i = n..1, print 1..i
12345
1234
123
12
1 ← 5 rows
In C# you solve it with two nested for loops: the outer loop picks the row length, the inner loop prints digits with Console.Write, then WriteLine() ends the row. Flip the outer loop upward for an ascending triangle (1, 12, 123…).
Approach
How to Solve It
Two ways to emit the same shape — start with nested loops, then optionally shorten with LINQ.
Method
Idea
Best for
Nested loops
Outer = length n..1, inner = digits 1..i via Write
Learning, interviews, exams
Enumerable.Range
Build a whole digit row in one call
Shorter demos once loops click
Pseudocode
Pseudocode
for i from rows down to 1:
for j from 1 to i:
print j (no newline)
print newline
for (i = 1; i <= rows; i++) with the same inner loop
Write vs WriteLine
API
Effect
Use for
Console.Write
Stays on the same line
Each digit j
Console.WriteLine
Ends the current line
After the inner loop
Try it
Live Preview
Change the row count and the descending triangle updates instantly — including the total digit count.
Whole numbers from 1 to 15. Tap a chip or type a value — the preview redraws as you go.
Live result5 rows · 15 digits
12345
1234
123
12
1
Trace
Worked Walkthrough — rows = 4
Trace each outer-loop value of i and the digits the inner loop prints.
i
Inner j
Printed row
Digits
4
1..4
1234
4
3
1..3
123
3
2
1..2
12
2
1
1..1
1
1
Total digits are 4+3+2+1 = 10 — the triangular number n(n+1)/2.
Code
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 shrinks the length; inner loop prints digits 1..i.
C#
using System;
namespace MyApp
{
class Program
{
static void Main(string[] args)
{
int rows = 5;
int i, j;
for (i = rows; i >= 1; i--)
{
for (j = 1; j <= i; j++)
{
Console.Write(j);
}
Console.WriteLine();
}
}
}
}
Output
12345
1234
123
12
1
How It Works
1. Shrink the count.for (i = rows; i >= 1; i--) yields 5, 4, 3, 2, 1.
2. Print digits. When i = 5, the inner loop prints 12345; when i = 1, just 1.
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 = rows; i >= 1; i--)
{
for (j = 1; j <= i; j++)
{
Console.Write(j);
}
Console.WriteLine();
}
}
}
}
2. Same nested loops. Four rows start at 1234 and end at 1.
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 = rows; i >= 1; i--)
{
Console.WriteLine(string.Join("", Enumerable.Range(1, i)));
}
}
}
}
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.
grow not shrink
for (i = 1; i <= rows; i++)
That outer loop grows the triangle (1, 12, 123…). Keep i = rows; i >= 1; i-- for this pattern.
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 < i instead of j <= i
You drop the last digit on every row (e.g. 1234 becomes 123).
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.
Analysis
Time and Space Complexity
Program
Time
Extra 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.
Remember
Key Takeaways
Rule: for i = n..1, print digits 1..i with Write.
Count down: the outer loop starts at rows so the first line is longest.
Write vs WriteLine: digits stay on the line; WriteLine advances after each row.
Next step: Program 2 shifts the start digit left each row.
One line: for each length from n down to 1, print 1..i with Write, then WriteLine.
Frequently Asked Questions
The outer loop runs i from rows down to 1. For each row i, the inner loop runs j from 1 to i and prints j with Console.Write. Row rows prints 1..rows, the next row prints one fewer digit, down to a single 1.
Counting down makes the first row the longest. for (i = rows; i >= 1; i--) sets i to the full width first, then shrinks by one each line — matching 12345, 1234, 123, 12, 1.
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.
Change the outer loop to for (i = 1; i <= rows; i++). Keep the inner loop as for (j = 1; j <= i; j++) Console.Write(j). The first row then has one digit and the last row has rows digits.
O(n²) where n is the number of rows. Total Console.Write calls equal 1+2+…+n = n(n+1)/2.
Yes. Console.WriteLine(string.Join("", Enumerable.Range(1, i))) prints a full row in one call. Nested loops are better for learning; LINQ is a handy shortcut later.
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?
Row i prints digits 1 through i. The outer loop counts down from rows, so the first line is longest and each row shortens by one digit — still O(n²) total prints.