Shape Rule
i..rows per row
Row 1 prints 12345, row 2 prints 2345, row 3 prints 345, and so on until a single 5.

The left-shifted descending number triangle changes the inner loop start value each row — a natural step after the classic descending triangle in Program 1. This tutorial covers the shape rule, loop structure, a live preview, algorithm steps, worked PHP examples, edge cases, and complexity.
i..rows per row
Row 1 prints 12345, row 2 prints 2345, row 3 prints 345, and so on until a single 5.
1..rows
for ($i = 1; $i <= $rows; $i++) picks the starting digit for each row.
Start at i
for ($j = $i; $j <= $rows; $j++) prints digits from $i through $rows.
Same line / next line
Digits use echo $j; end each row with echo PHP_EOL.
1–20 rows
Pick a row count and draw the left-shifted triangle instantly in the browser.
Complexity
Total digit prints = n(n+1)/2; extra memory stays O(1).
A left-shifted descending number triangle keeps the longest row on top but shifts the start digit right each line. With rows = 5, the output is 12345, 2345, 345, 45, 5.
In PHP the outer loop picks the row start i, the inner loop prints j from i to rows, then echo PHP_EOL moves to the next line.
It teaches how changing the inner loop start value reshapes the output — a key step after Program 1.
On row i, print digits i through rows.
for ($j = $i; $j <= $rows; $j++) — not $j = 1.
echo $j in the inner loop; echo PHP_EOL after.
Follow Program 1; continue to Program 3 (reverse descending triangle).
In short: for each row i from 1 to rows, print digits i..rows with echo $j, then call echo PHP_EOL.
Given a positive integer rows, print a left-shifted descending triangle: each row i shows digits from i through rows, with the outer loop counting from 1 up to rows.
// rows = 5 (conceptual shape)
// 12345
// 2345
// 345
// 45
// 5 | Item | Type | Description |
|---|---|---|
rows | int | Number of triangle lines to print (typically ≥ 1). |
| Printed output | text | Each row prints i..rows; the top row has rows digits, the bottom row has one digit. |
for i from 1 to rows:
for j from i to rows:
print j (no newline)
print newline | Approach | Idea | Best for |
|---|---|---|
| Nested loops | Outer rows + inner digits | Learning and interviews |
string row builder | Append digits then echo the row | Shorter production-style demos |
| Goal | Pattern |
|---|---|
| Walk each row | for ($i = 1; $i <= $rows; $i++) |
Print digits i..rows | for ($j = $i; $j <= $rows; $j++) echo $j; |
| End the row | echo PHP_EOL; |
| One-line row shortcut | $row .= $j loop |
| Program 1 variant | for ($i = $rows; $i >= 1; $i--) with $j = 1..$i |
Same triangle — different ways to emit characters.
same linePrints a digit without moving to the next line
new lineEnds the current row after all digits are printed
whole rowBuilds digits $i..$rows with $row .= $j
loops firstMaster nested loops before the string concatenation shortcut
Reach for this pattern when teaching how the inner loop start value changes the shape.
Natural follow-up after Program 1 — changes the inner loop start value.
Outer/inner bound practice with an immediate visual check.
Combine loops with fgets(STDIN) for a flexible row count.
Compare Program 1 (classic descending) and Program 3 (reverse descending) next.
This is a console teaching pattern — not how you build modern app screens.
Key benefit: one small program that locks in nested loops, output sequencing, and O(n²) thinking.
Choose a row count between 1 and 20 and draw the left-shifted number triangle in the browser.
Three complete PHP programs — fixed rows, user input, and a string concatenation shortcut. Click View Output to reveal sample console results.
Print five rows of the left-shifted triangle with nested loops.
rows = 5Hard-coded height — ideal for first demos and screenshots.
<?php
$rows = 5;
for ($i = 1; $i <= $rows; $i++) {
for ($j = $i; $j <= $rows; $j++) {
echo $j;
}
echo PHP_EOL;
} When i = 1, the inner loop prints 12345. When i = 2, it prints 2345, and so on until i = 5 prints 5. echo PHP_EOL after the inner loop starts the next row.
Let the user choose the height at runtime.
Read the row count with (int) trim(fgets(STDIN)) (call is_numeric(trim($line)) first in real apps).
<?php
echo "Enter the number of rows: ";
$rows = (int) trim(fgets(STDIN));
for ($i = 1; $i <= $rows; $i++) {
for ($j = $i; $j <= $rows; $j++) {
echo $j;
}
echo PHP_EOL;
} Same nested-loop core as Example 1; only the source of rows changes. Non-numeric input leaves rows unset if you skip is_numeric() checks — always check it in safer labs.
Same left-shifted shape by building each row with string concatenation before printing.
String Concatenation Row BuilderAppend each digit with $row .= $j, then print the full row with echo PHP_EOL.
<?php
$rows = 5;
for ($i = 1; $i <= $rows; $i++) {
$row = '';
for ($j = $i; $j <= $rows; $j++) {
$row .= $j;
}
echo $row . PHP_EOL;
} $row .= $j collects each digit, then echo PHP_EOL prints the whole row at once. Same nested-loop structure as Example 1; a compact alternative to repeated echo $j. Keep either style for exams that want both loop bounds visible.
Set $rows = 5; and use fgets(STDIN) when reading input. Set rows (fixed or from input).
for ($i = 1; $i <= $rows; $i++) selects the starting digit for each row.
for ($j = $i; $j <= $rows; $j++) prints digits $i..$rows with echo $j.
echo PHP_EOL ends the row so the next outer iteration starts fresh.
Total digit prints: 1+2+…+n = n(n+1)/2 — O(n²) time, O(1) extra memory.
rows = 4Trace each outer-loop value of i (counting up) and the inner j range on each row.
i | Inner j range | Printed row | Digits this row |
|---|---|---|---|
1 | 1..4 | 1234 | 4 |
2 | 2..4 | 234 | 3 |
3 | 3..4 | 34 | 2 |
4 | 4..4 | 4 | 1 |
Total digit prints: 4 + 3 + 2 + 1 = 10 = 4×5/2.
Where this tiny pattern (and its loop structure) shows up beyond the homework prompt.
Clearest visual proof that outer and inner bounds interact.
Example: change j <= rows and watch the shape change.
Foundation for inverted, pyramid, diamond, and hollow variants.
Example: change inner start from j = i to j = 1 and compare with Program 1.
Practice echo vs PHP_EOL without complex math.
Example: put echo PHP_EOL inside the inner loop by mistake.
Swap digits for letters, stars, or spaced output once the loop works.
Example: print j + " " for spaced digits on each row.
Triangular totals make O(n²) concrete for beginners.
Example: count printed digits for n = 10 → 55.
Pair the pattern with fgets(STDIN) and is_numeric() checks and positive-row checks.
Example: reject rows <= 0 and re-prompt.
Pro Tip: when an interviewer asks for patterns, explain the outer/inner roles first — then write the loops. The story matters as much as the code.
Why this pattern earns a permanent spot in beginner C courses.
Wrong bounds show up immediately as a broken staircase.
Only loops and console output — no arrays or math libraries.
Invert, center, hollow, or change the fill character with small edits.
Streaming output needs no storage beyond loop counters.
Pro Tip: learn the nested-loop version first; treat the string-concatenation row builder as a polish shortcut afterward.
Small habits that keep number-pattern code clean.
Use rows (or n) and keep i/j for row/column — or rename to row/col.
Call is_numeric(trim($line)) so bad input does not leave rows uninitialized.
Only call echo PHP_EOL after the inner loop finishes the row.
for ($j = $i; $j <= $rows; $j++) matches “row $i prints digits $i..$rows” naturally.
Trace rows = 3 on paper before coding larger demos.
Pro Tip: if the output is a vertical list of single digits, you almost certainly put echo PHP_EOL inside the inner loop.
Mistakes that commonly break left-shifted number patterns.
Each digit lands on its own line — you get a column, not a triangle.
→ Use echo $j for digits; echo PHP_EOL only after the inner loop.
j = 1 prints Program 1’s shape; j <= i prints a growing triangle.
→ For this shape, keep for ($j = $i; $j <= $rows; $j++).
Omitting echo PHP_EOL glues every digit onto one endless line.
→ Always end the row after the inner loop.
Letters or empty input leave rows uninitialized.
→ Prefer is_numeric() and re-prompt on failure.
Switching to i = 0 without adjusting the inner bound prints an empty first row or wrong counts.
→ If 0-based, start inner at j = i and end at rows - 1 or adjust bounds.
Check these inputs before calling the solution done.
Output is just 1 on one line.
Outer loop never runs — print nothing or show a message.
rows < 0Treat as invalid; re-prompt instead of silent empty output.
Output grows as n²/2 characters — fine for labs, noisy for huge n.
Unchecked fgets(STDIN) leaves rows unset — call is_numeric(trim($line)) first.
Try echo $j . " " for spaces between numbers.
Try these variations to lock in the pattern.
is_numeric(trim($line)) until rows >= 1echo $j . " " between digitsn(n+1)/2 — hence O(n²) time.echo $j stays on the line; echo PHP_EOL advances — mix them carefully.rows > 0 for interactive programs; rows = 1 should print a single 1.Quick Takeaway: outer loop picks start i, inner loop prints digits i..rows, then break the line — that is the whole pattern.
| Program | Time | Extra space |
|---|---|---|
| Nested loops (Examples 1–2) | O(rows²) | O(1) |
string concatenation row builder (Example 3) | O(rows²) | O(rows) per row string (temporary) |
The left-shifted descending number triangle is a small nested-loop exercise with lasting payoff: changing the inner start value, echo vs PHP_EOL, and O(n²) intuition. Master the classic two-loop version, then optionally build each row with string concatenation.
Practice the three examples above, then continue to Program 3 for the reverse descending number triangle.
Row i prints i..rows — keep echo $j for digits and echo PHP_EOL for the break, and validate row counts when reading input.
j = i inner start before codingecho $j for digits and echo PHP_EOL after each rowrows ≥ 1 for interactive programsis_numeric(trim($line)) before using rowsecho PHP_EOL inside the inner digit loopj = 1 when you meant left-shifted shaperows = 1 edge casePrint the triangle the beginner-friendly way.
Row i prints i..rows
DefinitionControls each row
Codej = i, not j = 1
CodeEnds each row
I/OO(n²) time
AnalysisEach row starts at $i and prints through $rows, so the left edge shifts right each line — still O(n²) total prints for n rows.
Move on to the reverse descending number triangle in the PHP number-pattern series.
12 people found this page helpful