Rotating Number Pattern in JavaScript

Beginner
⏱️ 9 min read
📚 Updated: Sep 2026
🎯 3 Code Examples
🚀 Live Preview
Nested Loops

What You’ll Learn

Program 50 prints a mixed number triangle: each row combines descending i..2 with ascending 1..(rows-i+1) — a natural step after Program 49’s multiplication triangle. This tutorial covers two inner loops per row, a live preview, worked JavaScript examples, edge cases, and complexity.

Shape Rule

Two halves per row

Row i prints descending i..2, then ascending 1..(rows-i+1) — always rows digits total.

Outer Loop

i = 1..rows

for (let i = 1; i <= n; i++) picks the current row index.

Descending Loop

j = i..2

for (let j = i; j > 1; j--) appends the descending half (skipped when i = 1).

Ascending Loop

k = 1..(rows-i+1)

for (let k = 1; k <= n + 1 - i; k++) appends the ascending half on each row.

Live Preview

rows = 3..9

Pick row count and draw the mixed number triangle in the browser.

O(n²)

Complexity

Total prints = n×n = n² — each row has exactly n digits.

Introduction

A mixed number triangle pattern builds each row from two halves: append descending i..2, then ascending 1..(rows-i+1). With rows = 5, you get 12345, 21234, 32123, 43212, 54321.

In JavaScript, nested loops handle this: outer i = 1..n, inner descending j = i..2, inner ascending k = 1..(n-i+1), then console.log(line).

Why it matters?

It bridges Program 49’s multiplication triangle to patterns with two inner loops per row — combining descending and ascending digit sequences.

Key Highlights

Descending half

j runs i..2.

Ascending half

k runs 1..(rows-i+1).

vs Program 49

Program 49 prints i*j products; Program 50 concatenates digit sequences.

Series Foundation

Follow Program 49; continue to Program 51 next.

In short: outer i = 1..rows, inner descending j = i..2, inner ascending k = 1..(rows-i+1), then console.log(line).

📝 Problem & Approach

Given row count rows = 5, print a mixed number triangle — row i shows descending i..2 then ascending 1..(rows-i+1).

JavaScript
// n = 5
// 12345
// 21234
// 32123
// 43212
// 54321

Inputs & Outputs

ItemTypeDescription
rowsnumberHow many triangle rows to print.
i (outer)numberCurrent row index — runs from 1 to rows.
j (descending)numberPrints i..2 — skipped when i = 1.
k (ascending)numberPrints 1..(rows-i+1) on each row.
Row lengthnumberAlways rows digits per row.

Minimal workflow

JavaScript
for (let i = 1; i <= rows; i++) {
  let line = "";
  for (let j = i; j > 1; j--) line += j;
  for (let k = 1; k <= rows + 1 - i; k++) line += k;
  console.log(line);
}

Approach comparison

ApproachIdeaBest for
Two inner loopsDescending j = i..2, ascending k = 1..(rows-i+1)Learning and interviews
User-input rowsconst n = parseInt(prompt(), 10)Flexible row count
Compact tracerows = 3 on paper firstQuick dry-runs before full demo
Spaced variantline += j + " "Easier reading per row

⚡ Quick Reference

GoalPattern
Outer loopfor (let i = 1; i <= n; i++)
Descending halffor (let j = i; j > 1; j--) { line += j; }
Ascending halffor (let k = 1; k <= n + 1 - i; k++) { line += k; }
End rowconsole.log(line);
Row 1 special caseDescending loop skipped — only ascending prints
Program 49 contrastProgram 49 prints i*j products; Program 50 uses digit sequences

📋 Fixed Rows vs User Input vs Compact Trace

Same triangle — three ways to set row count and format output.

Fixed rows
rows = 5

Hard-coded height for demos

User input
parseInt(prompt())

Read row count with user input

Compact trace
rows = 3

Quick dry-run on paper

Descending
j = i..2

First inner loop per row

Ascending
k = 1..(rows-i+1)

Second inner loop per row

Context

When This Pattern Shows Up

Reach for this pattern when teaching two inner loops per row and combining descending with ascending sequences.

  1. Post Program 49 exercise

    Natural follow-up after Program 49’s multiplication triangle — introduces two inner loops per row.

  2. Rotating digit sequences

    Each row looks “rotated” because the descending prefix shifts while the ascending tail fills the rest.

  3. Two halves per row

    Total logs = n×n = n² — each row has exactly n digits.

  4. Gateway to variants

    Compare Program 49 (multiplication triangle) with this mixed number triangle, then continue to Program 51.

  5. Not a UI layout tool

    This is a console teaching pattern — not how you build modern app screens.

Key benefit: one small program that locks in two inner loops per row and O(n²) thinking.

🔮 Live Preview

Choose row count between 3 and 9 and draw the mixed number triangle in the browser.

Try 4, 5, or 7. Max up to 9 in this preview.

Live result
Press "Draw pattern".

Examples Gallery

Three complete JavaScript programs — fixed n, user input, and a compact trace demo. Click View Output to reveal sample console results, or Try it Yourself to run in the browser.

📚 Getting Started

Print five rows of the mixed number triangle with two inner loops per row.

Example 1 — Fixed n = 5

Hard-coded row count — descending i..2 then ascending 1..(n-i+1) on each line.

JavaScript
const n = 5;

for (let i = 1; i <= n; i++) {
  let line = "";

  for (let j = i; j > 1; j--) {
    line += j;
  }

  for (let k = 1; k <= n + 1 - i; k++) {
    line += k;
  }

  console.log(line);
}
Try it Yourself

How It Works

When i = 2, the first loop prints 2, then the second prints 1234 — output 21234. When i = 1, the descending loop is skipped and only 12345 prints.

📈 User Input

Read row count with prompt() and Number.isFinite validation.

Example 2 — User Input n

Read n with prompt() and validate the result.

JavaScript
const nInput = prompt("Enter n:");
const n = parseInt(nInput, 10);

if (!Number.isFinite(n) || n < 1) {
  console.log("Please enter a positive integer.");
} else {
  for (let i = 1; i <= n; i++) {
    let line = "";

    for (let j = i; j > 1; j--) {
      line += j;
    }

    for (let k = 1; k <= n + 1 - i; k++) {
      line += k;
    }

    console.log(line);
  }
}
Try it Yourself

How It Works

Same two-loop core as Example 1; only the source of rows changes from a literal to user input.

⚡ Compact Trace

Smaller row count for quick tracing on paper or in interviews.

Example 3 — Compact n = 3

Use n = 3 to trace both inner loops quickly before scaling to 5 rows.

JavaScript
const n = 3;

for (let i = 1; i <= n; i++) {
  let line = "";

  for (let j = i; j > 1; j--) {
    line += j;
  }

  for (let k = 1; k <= n + 1 - i; k++) {
    line += k;
  }

  console.log(line);
}
Try it Yourself

How It Works

With only three rows you can trace every iteration of both inner loops on paper before running the full rows = 5 demo.

🧠 How the Algorithm Prints Rows

1

Choose row count

No imports needed. Set n = 5 or read from user input — controls pattern height.

Setup
2

Outer loop — row index

for (let i = 1; i <= n; i++) — selects which row to log.

Outer
3

Two inner loops

for (let j = i; j > 1; j--) appends descending digits, then for (let k = 1; k <= n + 1 - i; k++) appends ascending digits.

Inner
4

New line per row

console.log(line) after both inner loops finish each row.

Break
=

Mixed number triangle complete

Total prints = n×n = n²O(n²) time, O(1) extra memory.

🔎 Worked Walkthrough — rows = 5

Trace each row’s descending and ascending halves and the full line output.

iDescending (j)Ascending (k)Row output
1(skip)1..512345
221..421234
33,21..332123
44,3,21..243212
55,4,3,2154321

Each row prints exactly rows digits — descending count plus ascending count always equals rows.

Use Cases

Where this tiny pattern (and its loop structure) shows up beyond the homework prompt.

1. Teaching Nested Loops

Inner bound grows with outer index — classic nested-loop exercise.

Example: trace row i = 4 in the walkthrough table.

2. Multiplication Tables

Row i is the i-times table — visual arithmetic bridge.

Example: row 5 ends with 54321 — descending 5432 plus ascending 1.

3. Output Formatting Drills

Practice line += j vs console.log(line) with two inner loops per row.

Example: put console.log(line) inside either inner loop by mistake.

4. Two Halves Per Row

Total logs = n×n = n² — each row always has n digits.

Example: 10 rows log 100 digits total.

5. Complexity Intuition

Fixed row width makes O(n²) concrete — count digit logs for n rows.

Example: 5 rows = 5×5 = 25 digit logs.

6. Input Validation Labs

Pair the pattern with Number.isFinite and positive-row checks after parseInt(prompt()).

Example: reject rows <= 0 and re-prompt.

Pro Tip: when an interviewer asks for patterns, explain outer/inner roles first — then write the loops. The story matters as much as the code.

Advantages

Why this pattern earns a permanent spot in beginner JavaScript courses.

  1. 1. Instant Visual Feedback

    Wrong inner bounds show up immediately as a broken triangle.

  2. 2. Real Math Connection

    Each row combines descending and ascending halves — not abstract loop drill.

  3. 3. Easy to Extend

    Change rows, use fixed-width format, or switch to full rectangular table.

  4. 4. O(1) Extra Memory

    Streaming output needs no storage beyond loop counters.

Pro Tip: trace row i = 4 on paper — watch how inner j runs from 1 to 4 producing 4, 8, 12, 16.

Usage Tips

Small habits that keep number-pattern code clean.

  1. 1. Two Inner Loops

    Descending j = i..2, then ascending k = 1..(rows-i+1) — each row always has rows digits.

  2. 2. Validate with Number.isFinite

    Avoid crashes when the user types letters instead of a number.

  3. 3. Newline After Both Loops

    Only call console.log(line) after both inner loops finish the row.

  4. 4. Fixed-Width Formatting

    Trace rows = 3 on paper before coding the full rows = 5 demo.

  5. 5. Dry-Run rows = 5

    Trace five rows on paper before coding the full 10-row demo.

Pro Tip: if the output is a vertical list of single numbers, you almost certainly put console.log(line) inside one of the inner loops.

Common Pitfalls

Mistakes that commonly break mixed number triangle patterns.

  1. 1. Newline Inside Inner Loop

    Each digit lands on its own line — you get a column, not a mixed triangle row.

    → Use line += j and line += k without spaces; console.log(line) only after both inner loops.

  2. 2. Wrong Inner Bound

    Using j <= rows every row makes a full rectangle, not a triangle.

    → Use for (let j = i; j > 1; j--) for descending, then for (let k = 1; k <= n + 1 - i; k++) for ascending.

  3. 3. Swapping i and j in Product

    j > 1 skips when i = 1, but order matters in other patterns — stay consistent.

    → Use j > 1 (not j >= 1) so row 1 skips the descending loop correctly.

  4. 4. Forgetting Newline After Row

    All digits print on one long line without row breaks.

    → Add console.log(line) after both inner loops complete.

  5. 5. Bare parseInt(prompt())

    Letters or empty input yield NaN with bare parseInt(prompt()).

    → Check Number.isFinite(n) and re-prompt on failure.

Edge Cases

Check these inputs before calling the solution done.

rows = 1

Single row

Output is just 1 on one line.

rows = 0

Empty output

Outer loop never runs — print nothing or show a message.

Negative

rows < 0

Treat as invalid; re-prompt instead of silent empty output.

rows = 5

Compact trace

Five rows ending with 54321 — good for dry-runs.

Bad input

Non-numeric input

Bare parseInt(prompt()) returns NaN — validate with Number.isFinite first.

Large rows

Wide output

Row 9 has 9 digits — output grows as total prints.

🎯 Practice Problems

Try these variations to lock in the pattern.

1. Compare with Program 49

  • Program 49 prints i*j products on each row
  • Program 50 uses two inner loops with digit sequences

2. Change rows

  • Try rows = 4 or rows = 8 in the live preview
  • Same nested loops, different triangle size

3. Next in series

  • Continue with Program 51
  • Build on mixed number patterns

4. Spaced output

  • Add spaces with line += j + " "
  • Same loops, wider visual spacing

Notes

  • Two inner loops. Outer: i = 1..rows. Descending: j = i..2. Ascending: k = 1..(rows-i+1).
  • line += j and line += k build the row; console.log(line) advances — call it only after both inner loops finish.
  • Validate rows > 0 for interactive programs; rows = 1 prints a single 1.
  • Total prints = n×n = n² for n rows — each row has exactly n digits.

Quick Takeaway: outer i = 1..rows, inner descending j = i..2, inner ascending k = 1..(rows-i+1), then console.log(line).

⏱️ Time and Space Complexity

ProgramTimeExtra space
Nested loops (Examples 1–3)O(n²)O(1)
Total digit logs for n rowsO(1)
Wrap Up

🎉 Conclusion

The mixed number triangle is a natural follow-up to Program 49: two inner loops per row combining descending and ascending digit sequences. Master the fixed-rows version, then try user input and the compact 3-row trace.

Practice the three examples above, then continue to Program 51 for the next pattern in the series.

Row i prints descending i..2 then ascending 1..(rows-i+1) — always rows digits total.

💡 Best Practices

✅ Do

  • Outer: for (let i = 1; i <= n; i++)
  • Descending: for (let j = i; j > 1; j--) { line += j; }
  • Ascending: for (let k = 1; k <= n + 1 - i; k++) { line += k; }
  • Call console.log(line) after both inner loops
  • Validate rows > 0 for interactive programs

❌ Don’t

  • Call console.log(line) inside either inner loop
  • Use j >= 1 in descending loop when you meant j > 1
  • Forget the row break after both inner loops
  • Ignore bad input in user-facing demos
  • Skip the rows = 3 dry-run before coding rows = 5

Key Takeaways

Knowledge Unlocked

Five things to remember about this mixed number triangle

Print the pattern the beginner-friendly way.

5
Core concepts
02

Outer loop

i = 1..rows

Code
03

Inner loop

j = i..2, k = 1..(rows-i+1)

Code
04

Row length

Always rows digits

Logic
O 05

Complexity

O(n²) time

Analysis

❓ Frequently Asked Questions

Each row logs two parts: first a descending sequence from i down to 2, then an ascending sequence from 1 up to (n - i + 1). Row 2 becomes 2 + 1234 = 21234.
One inner loop appends the descending part (j = i down to > 1). The other appends the ascending part (k = 1..(n-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 appends 1..n — a full ascending line.
The descending loop appends i first. For i = 2, that is 2. Then the ascending loop appends 1..(n-2+1) = 1..4, giving 21234.
Change n or read it from user input with parseInt(prompt()) — see Example 2.
O(n²) for n rows because each row logs n digits and there are n rows — total logs = n × n = n².
Program 49 logs i*j products on each row. Program 50 concatenates digit sequences — descending then ascending — with no multiplication.
Both work for the descending loop: for (let j = i; j > 1; j--) and for (let j = i; j >= 1; j--) with j > 1 check append the same i..2 sequence.
Use parseInt with Number.isFinite. Bare parseInt(prompt()) returns NaN on bad input.
One row logs 1 — the descending loop is skipped and the ascending loop appends only 1.

Did you Know? 🔊

Each row combines two sequences: descending i..2, then ascending 1..(n-i+1). Row 2 prints 21234; row 5 prints 54321 — still O(n²) total logs for n rows.

Continue to Program 51

Move on to the next pattern in the JavaScript 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