Shape Rule
Two halves per row
Row i prints descending i..2, then ascending 1..(rows-i+1) — always rows digits total.

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.
Two halves per row
Row i prints descending i..2, then ascending 1..(rows-i+1) — always rows digits total.
i = 1..rows
for (let i = 1; i <= n; i++) picks the current row index.
j = i..2
for (let j = i; j > 1; j--) appends the descending half (skipped when i = 1).
k = 1..(rows-i+1)
for (let k = 1; k <= n + 1 - i; k++) appends the ascending half on each row.
rows = 3..9
Pick row count and draw the mixed number triangle in the browser.
Complexity
Total prints = n×n = n² — each row has exactly n digits.
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).
It bridges Program 49’s multiplication triangle to patterns with two inner loops per row — combining descending and ascending digit sequences.
j runs i..2.
k runs 1..(rows-i+1).
Program 49 prints i*j products; Program 50 concatenates digit sequences.
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).
Given row count rows = 5, print a mixed number triangle — row i shows descending i..2 then ascending 1..(rows-i+1).
// n = 5
// 12345
// 21234
// 32123
// 43212
// 54321 | Item | Type | Description |
|---|---|---|
rows | number | How many triangle rows to print. |
i (outer) | number | Current row index — runs from 1 to rows. |
j (descending) | number | Prints i..2 — skipped when i = 1. |
k (ascending) | number | Prints 1..(rows-i+1) on each row. |
| Row length | number | Always rows digits per row. |
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 | Idea | Best for |
|---|---|---|
| Two inner loops | Descending j = i..2, ascending k = 1..(rows-i+1) | Learning and interviews |
| User-input rows | const n = parseInt(prompt(), 10) | Flexible row count |
| Compact trace | rows = 3 on paper first | Quick dry-runs before full demo |
| Spaced variant | line += j + " " | Easier reading per row |
| Goal | Pattern |
|---|---|
| Outer loop | for (let i = 1; i <= n; i++) |
| Descending half | for (let j = i; j > 1; j--) { line += j; } |
| Ascending half | for (let k = 1; k <= n + 1 - i; k++) { line += k; } |
| End row | console.log(line); |
| Row 1 special case | Descending loop skipped — only ascending prints |
| Program 49 contrast | Program 49 prints i*j products; Program 50 uses digit sequences |
Same triangle — three ways to set row count and format output.
rows = 5Hard-coded height for demos
parseInt(prompt())Read row count with user input
rows = 3Quick dry-run on paper
j = i..2First inner loop per row
k = 1..(rows-i+1)Second inner loop per row
Reach for this pattern when teaching two inner loops per row and combining descending with ascending sequences.
Natural follow-up after Program 49’s multiplication triangle — introduces two inner loops per row.
Each row looks “rotated” because the descending prefix shifts while the ascending tail fills the rest.
Total logs = n×n = n² — each row has exactly n digits.
Compare Program 49 (multiplication triangle) with this mixed number triangle, then continue to Program 51.
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.
Choose row count between 3 and 9 and draw the mixed number triangle in the browser.
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.
Print five rows of the mixed number triangle with two inner loops per row.
n = 5Hard-coded row count — descending i..2 then ascending 1..(n-i+1) on each line.
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);
} 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.
Read row count with prompt() and Number.isFinite validation.
Read n with prompt() and validate the result.
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);
}
} Same two-loop core as Example 1; only the source of rows changes from a literal to user input.
Smaller row count for quick tracing on paper or in interviews.
n = 3Use n = 3 to trace both inner loops quickly before scaling to 5 rows.
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);
} With only three rows you can trace every iteration of both inner loops on paper before running the full rows = 5 demo.
No imports needed. Set n = 5 or read from user input — controls pattern height.
for (let i = 1; i <= n; i++) — selects which row to log.
for (let j = i; j > 1; j--) appends descending digits, then for (let k = 1; k <= n + 1 - i; k++) appends ascending digits.
console.log(line) after both inner loops finish each row.
Total prints = n×n = n² — O(n²) time, O(1) extra memory.
rows = 5Trace each row’s descending and ascending halves and the full line output.
i | Descending (j) | Ascending (k) | Row output |
|---|---|---|---|
1 | (skip) | 1..5 | 12345 |
2 | 2 | 1..4 | 21234 |
3 | 3,2 | 1..3 | 32123 |
4 | 4,3,2 | 1..2 | 43212 |
5 | 5,4,3,2 | 1 | 54321 |
Each row prints exactly rows digits — descending count plus ascending count always equals rows.
Where this tiny pattern (and its loop structure) shows up beyond the homework prompt.
Inner bound grows with outer index — classic nested-loop exercise.
Example: trace row i = 4 in the walkthrough table.
Row i is the i-times table — visual arithmetic bridge.
Example: row 5 ends with 54321 — descending 5432 plus ascending 1.
Practice line += j vs console.log(line) with two inner loops per row.
Example: put console.log(line) inside either inner loop by mistake.
Total logs = n×n = n² — each row always has n digits.
Example: 10 rows log 100 digits total.
Fixed row width makes O(n²) concrete — count digit logs for n rows.
Example: 5 rows = 5×5 = 25 digit logs.
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.
Why this pattern earns a permanent spot in beginner JavaScript courses.
Wrong inner bounds show up immediately as a broken triangle.
Each row combines descending and ascending halves — not abstract loop drill.
Change rows, use fixed-width format, or switch to full rectangular table.
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.
Small habits that keep number-pattern code clean.
Descending j = i..2, then ascending k = 1..(rows-i+1) — each row always has rows digits.
Number.isFiniteAvoid crashes when the user types letters instead of a number.
Only call console.log(line) after both inner loops finish the row.
Trace rows = 3 on paper before coding the full rows = 5 demo.
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.
Mistakes that commonly break mixed number triangle patterns.
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.
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.
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.
All digits print on one long line without row breaks.
→ Add console.log(line) after both inner loops complete.
parseInt(prompt())Letters or empty input yield NaN with bare parseInt(prompt()).
→ Check Number.isFinite(n) and re-prompt on failure.
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.
Five rows ending with 54321 — good for dry-runs.
Bare parseInt(prompt()) returns NaN — validate with Number.isFinite first.
Row 9 has 9 digits — output grows as n² total prints.
Try these variations to lock in the pattern.
line += j + " "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.rows > 0 for interactive programs; rows = 1 prints a single 1.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).
| Program | Time | Extra space |
|---|---|---|
| Nested loops (Examples 1–3) | O(n²) | O(1) |
| Total digit logs for n rows | n² | O(1) |
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.
for (let i = 1; i <= n; i++)for (let j = i; j > 1; j--) { line += j; }for (let k = 1; k <= n + 1 - i; k++) { line += k; }console.log(line) after both inner loopsrows > 0 for interactive programsconsole.log(line) inside either inner loopj >= 1 in descending loop when you meant j > 1rows = 3 dry-run before coding rows = 5Print the pattern the beginner-friendly way.
Row i: i..2 then 1..(rows-i+1)
Definitioni = 1..rows
Codej = i..2, k = 1..(rows-i+1)
CodeAlways rows digits
LogicO(n²) time
AnalysisEach 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.
Move on to the next pattern in the JavaScript number-pattern series.
12 people found this page helpful