PHP Number Pattern (Decreasing then Increasing)

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

What Is This Pattern?

A mixed number triangle builds each row from two halves: descending $i..2, then ascending 1..($rows - $i + 1). Every row has exactly $rows digits — with $rows = 5 you get 12345, 21234, 32123, 43212, 54321.

Remember
Rule: print i..2, then 1..(rows-i+1)

12345
21234
32123
43212
54321     ← rows = 5

Unlike Program 49 (products $i*$j), this shape concatenates digit sequences — no multiplication.

How to Solve It

Outer loop picks row $i. Two inner loops fill the descending half, then the ascending half.

MethodIdeaBest for
Two inner loopsDescending $j = $i..2, then ascending $k = 1..($rows-$i+1)Learning, interviews, demos
Compact traceSame logic with $rows = 3Quick dry-runs on paper

Pseudocode

Pseudocode
for i from 1 to rows:
    for j from i down to 2:
        print j (no newline)
    for k from 1 to (rows - i + 1):
        print k (no newline)
    print newline

Cheat sheet

GoalPattern
Outer rowsfor ($i = 1; $i <= $rows; $i++)
Descending halffor ($j = $i; $j > 1; $j--) echo $j;
Ascending halffor ($k = 1; $k <= $rows + 1 - $i; $k++) echo $k;
End the rowecho PHP_EOL;
Digits per rowAlways $rows

Printing Numbers vs Starting a New Line

APIEffectUse for
echo $j / echo $kStays on the same lineEach digit
echo PHP_EOLEnds the current lineAfter both inner loops

Print digits without a newline, then end the row once. Putting echo PHP_EOL inside either inner loop turns the pattern into a vertical list.

Live Preview

Change the row count and the mixed triangle updates instantly.

Use rows from 1 to 9 (single digits stay tidy). Tap a chip or type a value — the preview redraws as you go.

Live result 5 rows · 25 digits
12345
21234
32123
43212
54321

Worked Walkthrough

Trace row $i = 3 with $rows = 5 — descending then ascending.

HalfLoopPrintsLine so far
Descending$j = 3, 23, 232
Ascending$k = 1..(5-3+1) = 1..31, 2, 332123

When $i = 1, the descending loop never runs — the whole row is just 1..$rows. When $i = $rows, the ascending loop prints only 1, so the row is $rows..(2)1.

PHP Programs

Three complete programs: fixed $rows = 5, CLI input, and a compact $rows = 3 demo. Use View Output to reveal sample results.

Example 1 — Fixed $rows = 5

Hard-coded height — descending half, then ascending half, on every row.

PHP
<?php
$rows = 5;

for ($i = 1; $i <= $rows; $i++) {
    for ($j = $i; $j > 1; $j--) {
        echo $j;
    }
    for ($k = 1; $k <= $rows + 1 - $i; $k++) {
        echo $k;
    }
    echo PHP_EOL;
}
?>

How It Works

1. Outer loop picks the row. $i runs from 1 to 5 — one full line per value.

2. Descending half first. $j runs from $i down past 1, printing $i..2 (skipped when $i = 1).

3. Ascending half fills the rest. $k runs from 1 to $rows + 1 - $i, then echo PHP_EOL ends the row.

Example 2 — User Input Rows

Read the row count at runtime — both halves scale automatically.

PHP
<?php
echo "Enter the number of rows: ";
$input = trim(fgets(STDIN));

if (!is_numeric($input) || (int) $input <= 0) {
    echo "Please enter a positive integer." . PHP_EOL;
    exit(1);
}

$rows = (int) $input;

for ($i = 1; $i <= $rows; $i++) {
    for ($j = $i; $j > 1; $j--) {
        echo $j;
    }
    for ($k = 1; $k <= $rows + 1 - $i; $k++) {
        echo $k;
    }
    echo PHP_EOL;
}
?>

How It Works

1. Same two-loop core. Only the source of $rows changes from a literal to CLI input.

2. Width follows $rows. Entering 4 yields four digits on every line.

3. Safer input tip. Cap demos for readable output:

Safer input tip
if (!is_numeric($input) || (int) $input < 1 || (int) $input > 9) {
    echo "Enter a whole number from 1 to 9." . PHP_EOL;
    exit(1);
}

Example 3 — Compact $rows = 3

Smaller height for quick tracing on paper or in interviews.

PHP
<?php
$rows = 3;

for ($i = 1; $i <= $rows; $i++) {
    for ($j = $i; $j > 1; $j--) {
        echo $j;
    }
    for ($k = 1; $k <= $rows + 1 - $i; $k++) {
        echo $k;
    }
    echo PHP_EOL;
}
?>

How It Works

1. Only three rows. Easy to dry-run every descending and ascending step by hand.

2. Same formula. Nothing changes except $rows — proving the pattern scales.

3. Last row is fully descending. Row 3 prints 321 — 3 2 then 1.

Edge Cases & Pitfalls

Check these before calling the solution done.

Descending bound

Stop at 2, not at 1

Use $j > 1 (or $j >= 2). Going down to 1 duplicates the leading 1 from the ascending half.

Ascending length

Use $rows + 1 - $i

Wrong bounds break the fixed width of $rows digits per line.

Newline

Do not put PHP_EOL inside either inner loop

Call echo PHP_EOL only after both halves finish.

Between loops

No break between halves

Run both inner loops back-to-back. A newline between them splits each row in half.

rows = 1

Single value

Output is just 1. A good sanity check for input validation.

fgets

Check is_numeric

Bare (int) casts turn non-numeric strings into 0 — prefer is_numeric before casting.

Time and Space Complexity

ProgramTimeExtra space
Nested loops (Examples 1–3)O(n²)O(1)

Each of n rows prints exactly n digits, so total work is n². Only a few integers of extra memory.

Key Takeaways

  • Rule: print $i..2, then 1..($rows - $i + 1).
  • Fixed width: every row has exactly $rows digits.
  • Break the row: call echo PHP_EOL only after both inner loops.
  • Complexity: O(n²) time; O(1) extra space.

One line: for each row $i, print descending $i..2 then ascending 1..($rows-$i+1), then end the line.

Frequently Asked Questions

Each row prints two parts: first a descending sequence from $i down to 2, then an ascending sequence from 1 up to ($rows - $i + 1). Row 2 becomes 2 + 1234 = 21234.
One inner loop prints the descending part ($j = $i down to > 1). The other prints the ascending part ($k = 1..($rows-$i+1)). Splitting them keeps the two halves clear.
When $i = 1, the descending loop $j = $i; $j > 1 never runs. Only the ascending loop prints 1..$rows.
Program 49 prints $i*$j products on each row. Program 50 concatenates digit sequences — descending then ascending — with no multiplication.
Printing a digit stays on the same line. Printing PHP_EOL ends the current row. Digits use echo without a newline; the row break uses echo PHP_EOL after both inner loops.
O(n²) for n rows because each row prints n digits and there are n rows.
Both work for the descending loop — they print the same $i..2 sequence.
Use trim(fgets(STDIN)) and check is_numeric($input) before casting to int — see Example 2.

Did you know?

Each row combines two sequences: descending $i..2, then ascending 1..($rows-$i+1). Every row has exactly $rows digits — total prints = n², time O(n²).

Next: Alternating Ascending/Descending Triangle

Continue with the next pattern in the PHP number-pattern series.

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