Learn JavaScript

lesson ২ / ৯ · if, switch আর loop

Module ৪ · if, switch আর loop

প্রতিটা statement, একটা একটা করে

Freeপড়া

এই lesson-এ যা শিখবে

  • if থেকে label দেওয়া break পর্যন্ত control flow-এর প্রতিটা statement লিখতে পারবে, আর বলতে পারবে কোনটার test আর body কতবার চলে।
  • break ছাড়া একটা switch case কেন পরের case-এ গড়িয়ে পড়ে, বুঝিয়ে বলতে পারবে, আর যে case-গুলো একই body ভাগ করে, সেখানে এটা ইচ্ছে করে কাজে লাগাতে পারবে।
  • break দিয়ে loop আগেভাগে থামাতে পারবে, continue দিয়ে একটা pass-এর বাকিটা বাদ দিতে পারবে, আর label দিয়ে একসাথে দুইটা loop থেকে বের হতে পারবে।

Bob একটা switch লিখেছে, যেটা দিনের নম্বর থেকে দিনের নাম বের করে। Day 6-এর জন্য ও আশা করে একটাই লাইন, Saturday। অথচ program print করে তিনটা: Saturday, Sunday আর not a day। কোনো error আসে না, কারণ Bob যা লিখেছে JavaScript হুবহু তাই করেছে। কেন এমন হলো, আর এক শব্দের সমাধানটা কী, সেটা দেখাবে switch-এর অংশটা।

Control flow মানে statement-গুলো কোন ক্রমে চলে। Lesson 01 পুরো ছবিটা এঁকেছে: if, else, for loop আর for...of। এই lesson প্রতিটা statement-এর কাছে একবার করে যাবে: তার syntax, ছোট একটা উদাহরণ, আসল output আর তার খরচ। খরচ মানে উদাহরণের নিচে এক সারির একটা table: test আর body কতবার চলে।

if আর else

if আর else

if (condition) {
  runs when condition is truthy
} else {
  runs when condition is falsy
}
  • condition যেকোনো expression হতে পারে, সেটাকে truthy বা falsy হিসেবে পড়া হয় (Module 2)। else-এর অংশটা না দিলেও চলে।
const stock = 0;
if (stock > 0) {
  console.log("in stock:", stock);
} else {
  console.log("sold out");
}
if ("0") {
  console.log("the string \"0\" is truthy");
}
sold out
the string "0" is truthy
কতবারTestএকটা block
লাইনটায় যতবার পৌঁছায়, প্রতিবারএকবারদুইটার ঠিক একটা একবার চলে; else না থাকলে একটা, অথবা একটাও না

যেটায় চোখ রাখবে: খালি না এমন যেকোনো string truthy, "0"-ও। Falsy-র পুরো তালিকাটা Module 2-এ আছে। তাই if জিজ্ঞেস করে "truthy না falsy?", কখনো "এটা কি সংখ্যা 0?" না।

else if chain: প্রথম true condition-টাই জেতে

else if chain

if (first) {
  ...
} else if (second) {
  ...
} else {
  runs when no condition was truthy
}
  • Condition-গুলো উপর থেকে একটা একটা করে test হয়। প্রথম যেটা truthy, তার block চলে, বাকিগুলো বাদ।
const temp = 31;
if (temp >= 35) {
  console.log("very hot");
} else if (temp >= 25) {
  console.log("warm");
} else if (temp >= 15) {
  console.log("mild");
} else {
  console.log("cold");
}
if (temp >= 15) {
  console.log("Bob's order says: mild");
} else if (temp >= 25) {
  console.log("Bob's order says: warm");
}
warm
Bob's order says: mild
কতবারTest-গুলোএকটা block
k-টা conditionউপর থেকে নিচে, প্রথম truthy-টায় থামে: বড়জোর k বার (এখানে 2)ঠিক একটা, অথবা শেষে else না থাকলে একটাও না

যেটায় চোখ রাখবে: ক্রমটা। 31 তো 15-এর চেয়ে বড়, তাই Bob-এর chain প্রথম test-এই থেমে যায়, temp >= 25 পর্যন্ত আর পৌঁছায়ই না। Range নিয়ে কাজ করলে সবচেয়ে বড় সীমাটা আগে test করো, অথবা < দিয়ে সবচেয়ে ছোটটা আগে।

switch: একটা value, অনেকগুলো case

switch

switch (value) {
  case A:
    runs when value === A
    break;
  case B:
  case C:
    shared by B and C
    break;
  default:
    runs when no case matched
}
  • value-এর হিসাব হয় একবার, তারপর উপর থেকে প্রতিটা case-এর সাথে === দিয়ে মেলানো হয়, তাই কিছুই convert হয় না।
  • break দিয়ে switch থেকে বের হয়ে যায়। না দিলে run চলতেই থাকে, পরের case-এর লাইনগুলোতে ঢুকে পড়ে।

এই যে Bob-এর program, সত্যি সত্যি চালানো।

const day = 6;
switch (day) {
  case 5:
    console.log("Friday");
  case 6:
    console.log("Saturday");
  case 7:
    console.log("Sunday");
  default:
    console.log("not a day");
}
Saturday
Sunday
not a day

একটা case শুধু শুরু করার একটা জায়গা। switch খুঁজে বের করে প্রথম কোন case day-এর সমান, সেখানে লাফ দেয়, তারপর তার নিচের প্রতিটা লাইন চালায়। থামে একটা break পেলে, অথবা শেষের brace-এ পৌঁছালে। এর নাম fall-through, মানে নিচে গড়িয়ে পড়া। প্রতিটা case-এর শেষ লাইনে break; বসাও, তাহলে একই program শুধু Saturday print করবে।

Fall-through: break না থাকলে run case 6 থেকে নিচের প্রতিটা case-এ গড়িয়ে পড়ে day যখন 6: run কোথায় শুরু হয়, আর কোথায় থামে break নেই: গড়িয়ে পড়ে প্রতিটা case-এ break case 5: বাদ, 6 === 5 হলো false case 6: মিলেছে, print করে Saturday case 7: গড়িয়ে ঢোকে, print করে Sunday default: গড়িয়ে ঢোকে, print করে not a day switch-এর পরে 3টা লাইন print হয় case 5: বাদ, 6 === 5 হলো false case 6: print করে Saturday, তারপর break case 7: কখনো চলে না default: কখনো চলে না switch-এর পরে 1টা লাইন print হয়

Fall-through-এর একটাই সৎ ব্যবহার আছে: কয়েকটা case যখন একই body ভাগ করে। Case-গুলো মাঝে কিছু না রেখে একটার নিচে আরেকটা সাজাও, নিচের মাসগুলোর মতো। আর যে case-এ লাইন আছে অথচ ইচ্ছে করেই নিচে গড়ায়, তার গায়ে একটা // falls through comment দাও। তাহলে পরের পাঠক বুঝবে, এটা Bob-এর মতো bug না।

const month = 4;
let days;
switch (month) {
  case 2:
    days = 28;
    break;
  case 4:
  case 6:
  case 9:
  case 11:
    days = 30;
    break;
  default:
    days = 31;
}
console.log("month", month, "has", days, "days");

const plan = "pro";
switch (plan) {
  case "pro":
    console.log("cloud backup");
    // falls through
  case "basic":
    console.log("email support");
    break;
  default:
    console.log("no extras");
}
month 4 has 30 days
cloud backup
email support
কতবারমেলানোBody-গুলো
লাইনটায় যতবার পৌঁছায়, প্রতিবারvalue একবার, তারপর উপর থেকে case ধরে ধরে, যতক্ষণ না একটা === হয় (day 6: দুইবার মেলানো)মিলে যাওয়া case থেকে নিচে প্রথম break পর্যন্ত

যেটায় চোখ রাখবে: === মানে string "6" কখনো case 6-এর সাথে মেলে না, তাই চলে default ("যে ভুলগুলো সবাই করে"-র 3 নম্বর)। মাসের code-টা leap year ধরে না, আর default-এ পৌঁছায় তখনই, যখন সব case ফেল করে।

while: আগে test, তারপর body

while

while (condition) {
  body
}
  • প্রতিটা pass-এর আগে test চলে। প্রথমবারেই falsy হলে body একবারও চলে না।
let height = 16;
let bounces = 0;
while (height >= 1) {
  console.log("bounce to", height);
  height = height / 2;
  bounces++;
}
console.log("bounces:", bounces, "height now:", height);
bounce to 16
bounce to 8
bounce to 4
bounce to 2
bounce to 1
bounces: 5 height now: 0.5
কতবারTestBody
n-টা passn + 1 বার (এখানে 6: শেষবার উত্তর false)n বার, 0-ও হতে পারে (এখানে 5)

কয়টা pass লাগবে আগে থেকে জানা না থাকলে while loop মানায়: কখন থামতে হবে জানো, কয়বার ঘুরবে জানো না। যেটায় চোখ রাখবে: body-কে condition-টা false-এর দিকে ঠেলতে হবে। height = height / 2; মুছে দাও, loop আর কোনোদিন শেষ হবে না। Playground-এ এমন run time limit-এ গিয়ে থামে, মোটামুটি 10 সেকেন্ডে, "Time Limit Exceeded" দেখিয়ে।

do...while: body অন্তত একবার চলে

do...while

do {
  body
} while (condition);
  • আগে body চলে, তারপর test ঠিক করে আবার ঘুরবে কি না। শেষের parenthesis-এর পরের semicolon-টা খেয়াল করো।
let n = 10;
while (n < 5) {
  console.log("while body, n =", n);
  n++;
}
do {
  console.log("do body, n =", n);
  n++;
} while (n < 5);
console.log("after both loops, n =", n);
do body, n = 10
after both loops, n = 11

Condition n < 5 শুরু থেকেই false। While loop আগে জিজ্ঞেস করে, তাই তার body একবারও চলে না। do...while loop আগে body চালায়, তারপর জিজ্ঞেস করে। ধাপে ধাপে দেখো।

একটাই pass: body print করে do body, n = 10, আর n-কে 11 বানায়। তারপর test 11 < 5 উত্তর দেয় false, আর ঠিক একটা pass-এর পরেই loop শেষ।

PassPrint হলোBody-র পরে nTest n < 5
1do body, n = 101111 < 5 হলো false: থামো

দুইটা loop নিচে flowchart হিসেবে আঁকা। তফাত একটাই: test-টা কোথায় বসে।

while test করে body-র আগে; do...while test করে body-র পরে while: আগে test do...while: আগে body loop-এর আগে test? true body আবার false loop-এর পরে Body চলে 0 বা তার বেশি বার। loop-এর আগে body test? true false loop-এর পরে Body চলে 1 বা তার বেশি বার।
কতবারTestBody
n-টা pass, n অন্তত 1n বার, প্রতিটা pass-এর পরে একবার (এখানে 1)n বার, কখনো 0 না (এখানে 1)

যেটায় চোখ রাখবে: do...while তখনই নাও, যখন প্রশ্নটার মানে দাঁড়ানোর আগেই body-কে একবার চলতে হবে। প্রথম choice-এর আগে একবার menu দেখানো, বা 0-এর digit গোনা, এগুলোই চেনা উদাহরণ (Example 2)।

for: start, test, step

for

for (start; test; step) {
  body
}
for (;;) { ... }   all three parts empty: runs until a break
  • start চলে একবার, test প্রতিটা pass-এর আগে, step প্রতিটা pass-এর পরে (lesson 01)।
  • তিনটা অংশের যেকোনোটা খালি রাখা যায়। খালি test-কে true ধরা হয়।
for (let i = 3; i >= 1; i--) {
  console.log("countdown", i);
}
let k = 0;
for (; k < 5; ) {
  k += 2;
}
console.log("k is", k);
countdown 3
countdown 2
countdown 1
k is 6

দ্বিতীয় loop-এ start নেই, step-ও নেই: k বানানো হয়েছে আগেই, আর body সেটা বদলায়। এটা আসলে for loop-এর জামা পরা একটা while loop, তাই সোজা লেখো while (k < 5)। for (;;) হলো এমন loop, যার কোনো test-ই নেই। এটা টাইপের ভুল না: ভিতরের একটা break না আসা পর্যন্ত চলতে থাকে, break-এর অংশে যেমন দেখবে।

কতবারstart, test, stepBody
n-টা passstart একবার, test n + 1 বার, step n বার (countdown: 1, 4, 3)n বার (countdown: 3)

যেটায় চোখ রাখবে: counter হবে let। const counter প্রথম step-এই throw করে TypeError: Assignment to constant variable. (lesson 01)।

for...of: array বা string-এর প্রতিটা value

for...of

for (const item of list) {
  body, with item holding the next value
}
  • list হলো এমন কিছু, যার value-গুলো ক্রম ধরে সাজানো: একটা array (Module 7) বা একটা string (Module 3)।
  • প্রতিটা pass নতুন একটা item পায়, তাই এখানে const চলে, সাধারণ for loop-এর counter-এর মতো না।
const prices = [120, 45, 300];
let total = 0;
for (const price of prices) {
  total += price;
}
console.log("total:", total);
for (const ch of "hi!") {
  console.log(ch);
}
total: 465
h
i
!
কতবারTestBody
n-টা valueলিখতে হয় না; loop নিজে n + 1 বার পরের value চায়n বার (এখানে 3, তারপর আবার 3)

যেটায় চোখ রাখবে: for...of দেয় value, position না। Position-ও লাগলে i দিয়ে সাধারণ for loop লেখো। সাধারণ object-এর দেওয়ার মতো ক্রম ধরা value নেই, তাই for...of সেটা নিতে রাজি হয় না ("যে ভুলগুলো সবাই করে"-র 4 নম্বর)।

for...in: object-এর key, আর array-র ফাঁদ

for...in

for (const key in object) {
  body, with key holding the next key, always a string
}
  • Key হলো object-এর একটা অংশের নাম। Object শেখাবে Module 8; এখানে শুধু এক ঝলক।
const stock = { pens: 12, books: 0, bags: 5 };
for (const item in stock) {
  console.log(item, stock[item]);
}
const marks = [90, 75];
for (const i in marks) {
  console.log(i, typeof i, i + 1);
}
pens 12
books 0
bags 5
0 string 01
1 string 11

stock[item] সেই অংশটা পড়ে, যার নাম আছে item-এ। ফাঁদটা দ্বিতীয় loop-এ। Array-র উপর for...in position-গুলো দেয় string হিসেবে, "0" আর "1"। তাই i + 1 text জোড়ে আর দেয় "01", Module 2-এর সেই +-এর নিয়ম।

কতবারTestBody
k-টা keyলিখতে হয় নাk বার, প্রতিটা key-র জন্য একবার (এখানে 3, তারপর 2)

যেটায় চোখ রাখবে: for...in বানানো হয়েছে object-এর key-র জন্য। Array-র উপর value চাইলে for...of, position চাইলে সাধারণ for loop।

break: এখনই loop থেকে বের হও

break

break;   leaves the innermost loop or switch around it
const queue = [4, 9, -1, 7];
for (const ticket of queue) {
  if (ticket < 0) {
    console.log("bad ticket, stop");
    break;
  }
  console.log("serve", ticket);
}
let rounds = 0;
for (;;) {
  rounds++;
  if (rounds === 3) {
    break;
  }
}
console.log("rounds:", rounds);
serve 4
serve 9
bad ticket, stop
rounds: 3

Ticket 7 কখনো পড়াই হয় না: loop -1-এই শেষ। for (;;) loop-এর কোনো test নেই, তাই ওর break-ই বের হওয়ার একমাত্র দরজা।

কতবারTestBody
p নম্বর pass-এ breakতারপর আর কোনো test হয় নাp-টা pass, শেষটা মাঝপথে কাটা (ticket: 4-টার মধ্যে 3)

যেটায় চোখ রাখবে: break-কে থাকতে হবে একটা loop বা switch-এর ভিতরে। অন্য কোথাও থাকলে program শুরুই হয় না ("যে ভুলগুলো সবাই করে"-র 1 নম্বর)।

continue: পরের pass-এ চলে যাও

continue

continue;   skips the rest of this pass; the loop goes on
for (let seat = 1; seat <= 6; seat++) {
  if (seat % 3 === 0) {
    continue;
  }
  console.log("seat", seat);
}
seat 1
seat 2
seat 4
seat 5

Seat 3 আর 6 বাদ পড়েছে। For loop-এ continue লাফ দেয় step-এ, তাই seat++ তবুও চলে, আর loop এগিয়ে যায়।

কতবারTestBody
n-টা passআগের মতোই n + 1 বার (এখানে 7)শুরু হয় n বার, শেষ হয় শুধু যেখানে continue চলেনি (এখানে 6 আর 4)

যেটায় চোখ রাখবে: while loop-এ আলাদা কোনো step অংশ নেই। Counter বদলানোর লাইনের আগে continue বসালে সেই লাইনটাও বাদ পড়ে, আর loop কখনো শেষ হয় না।

Label দেওয়া break আর continue Intermediate

Label

name: for (...) {
  for (...) {
    break name;      leaves the loop called name
    continue name;   goes to the next pass of the loop called name
  }
}
  • Label হলো একটা loop-এর ঠিক আগে লেখা একটা নাম আর একটা colon। এটা ব্যবহার করে শুধু break আর continue।
outer: for (let row = 1; row <= 9; row++) {
  for (let col = 1; col <= 9; col++) {
    if (row * col > 20) {
      console.log("first product above 20:", row, "x", col);
      break outer;
    }
  }
}
rows: for (let row = 1; row <= 3; row++) {
  for (let col = 1; col <= 3; col++) {
    if (col > row) {
      continue rows;
    }
    console.log(row, col);
  }
}
first product above 20: 3 x 7
1 1
2 1
2 2
3 1
3 2
3 3

সাধারণ একটা break শুধু ভিতরের loop থেকে বের হতো, আর বাইরেরটা row 4 শুরু করে দিত। break outer একসাথে দুইটা থেকেই বের করে আনে। continue rows একটা row-এর বাকিটা ফেলে রেখে পরের row শুরু করে, আর তাতেই একটা ত্রিভুজ print হয়।

কতবারTest-গুলোভিতরের body
9 বাই 9 grid, 3 x 7-এ break outerbreak-এর পরে কোনো loop-এর আর test হয় না9 + 9 + 7 = 25 বার, 81 বার না

যেটায় চোখ রাখবে: label একটা loop-এর নাম, আর দুই মাথায় বানান হুবহু এক হতে হবে ("যে ভুলগুলো সবাই করে"-র 2 নম্বর)। return সহ ছোট একটা function (Module 5) প্রায়ই একই কাজ করে দেয়; loop-গুলো অনেক variable ভাগ করলে label-টাই মানায়।

Example 1: Alice-এর পড়ার plan

Alice দিনে 20 পাতা পড়ে। 130 পাতার একটা বই শেষ করতে কয় দিন লাগবে, আর শেষ দিনে কয় পাতা বাকি থাকবে?

const pages = 130;
const perDay = 20;
let read = 0;
let days = 0;
while (read < pages) {
  read += perDay;
  days++;
}
console.log("days:", days);
console.log("pages on the last day:", pages - (read - perDay));
days: 7
pages on the last day: 10

Loop শুরুর আগে কয়বার ঘুরবে জানা নেই, তাই while loop মানায়। ছয় দিনে ও পড়ে ফেলে 120 পাতা, আর সপ্তম দিনে শেষ 10 পাতা।

Run in Compiler
Example 2: do...while দিয়ে digit গোনা

একটা সংখ্যার digit গুনতে শেষের digit-টা কেটে ফেলতে থাকো, যতক্ষণ না কিছুই বাকি থাকে। 0-এরও একটা digit আছে, আর ঠিক এই কারণেই এই loop test করে শেষে।

const numbers = [0, 7, 42, 90210];
for (const number of numbers) {
  let n = number;
  let digits = 0;
  do {
    digits++;
    n = Math.floor(n / 10);
  } while (n > 0);
  console.log(number, "has", digits, "digit(s)");
}
0 has 1 digit(s)
7 has 1 digit(s)
42 has 2 digit(s)
90210 has 5 digit(s)

Math.floor(n / 10) শেষের digit-টা ফেলে দেয়, Module 1-এর সেই নিচের দিকে round করা। While loop হলে 0 > 0 test সাথে সাথেই ফেল করত, আর 0 পেত 0-টা digit।

Run in Compiler
Example 3: Amara-র bus card

Amara-র bus card শুরু হয় কিছু balance দিয়ে। প্রতিটা ride-এর একটা ভাড়া আছে। যে ride-এর ভাড়া balance-এ কুলায় না, সেটা বাতিল, card পরের ride-এর জন্য অপেক্ষা করে। Balance ঠিক 0 হয়ে গেলে সেদিনের মতো card আর কাজ করে না।

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

let balance = nextInt();
const rides = nextInt();
let paid = 0;
for (let ride = 1; ride <= rides; ride++) {
  const fare = nextInt();
  if (fare > balance) {
    out.push("ride " + ride + ": refused, balance " + balance);
    continue;
  }
  balance -= fare;
  paid++;
  out.push("ride " + ride + ": paid " + fare + ", balance " + balance);
  if (balance === 0) {
    out.push("card empty after ride " + ride);
    break;
  }
}
out.push("rides paid: " + paid);

console.log(out.join("\n"));
ride 1: paid 30, balance 70
ride 2: paid 50, balance 20
ride 3: refused, balance 20
ride 4: paid 20, balance 0
card empty after ride 4
rides paid: 3

ওই output-টা input-এর প্রথম লাইনে 100 5 আর পরের লাইনে 30 50 40 20 10 থাকলে। Ride 3-এর ভাড়া 40, অথচ বাকি আছে 20, তাই continue টাকা কাটার লাইনগুলো বাদ দিয়ে যায়। Ride 4 card খালি করে দেয়, তাই break loop শেষ করে, আর ride 5 পড়াই হয় না।

Run in Compiler

এটা কোথায় কাজে লাগে

  • Redux। Redux documentation reducer লেখে একটা switch (action.type) দিয়ে: প্রতিটা action-এর জন্য একটা case, আর একটা default, যেটা state না বদলে ফেরত দেয়।
  • ESLint। এর no-fallthrough rule recommended set-এ চালু থাকে, আর কোনো case পরেরটায় গড়িয়ে পড়লে ধরিয়ে দেয়। "falls through" লেখা একটা comment থাকলে rule বুঝে নেয়, গড়ানোটা ইচ্ছে করে।
  • TypeScript। noFallthroughCasesInSwitch compiler option চালু করলে, code আছে এমন case পরেরটায় গড়িয়ে পড়লে সেটা error হয়ে যায়। উপরের মাসগুলোর মতো খালি, সাজানো case-গুলো তবুও চলে।
  • Node-এর REPL। শুধু node টাইপ করলে খোলে একটা read, evaluate, print loop: একটা লাইন পড়ে, চালায়, ফল print করে, আর এভাবে চলতে থাকে যতক্ষণ না তুমি .exit লেখো। এটা এমন একটা loop, যেটা একটা sentinel না আসা পর্যন্ত চলে: sentinel মানে থামার একটা value, যেটা data-র অংশ না।

যে ভুলগুলো সবাই করে

১. Loop-এর বাইরে break।

const stock = 0;
if (stock === 0) {
  console.log("sold out");
  break;
}

কোনো লাইন চলার আগেই program থেমে যায়: SyntaxError: Illegal break statement। if তো loop না, তাই break-এর বের হওয়ার মতো কিছু নেই। ওটা মুছে দাও, অথবা বাকি কাজটা একটা else-এ রাখো। তুমি এটা লিখবে, কারণ break শুনলে মনে হয় "এখানেই থামো"।

২. এমন label-এ continue, যেটা আসলে নেই।

rows: for (let r = 1; r <= 2; r++) {
  for (let c = 1; c <= 2; c++) {
    if (c === 2) {
      continue row;
    }
    console.log(r, c);
  }
}

কোনো লাইন চলার আগেই program থেমে যায়: SyntaxError: Undefined label 'row'। Label-টা rows, অথচ continue row এমন একটা loop-এর নাম বলছে, যেটা নেই। দুই মাথায় বানান এক রাখো। ভুলটা হবে, কারণ নাম দুইটায় তফাত মাত্র একটা অক্ষর।

৩. Number-এর case-এর সাথে token-এর string।

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

const choice = next();
switch (choice) {
  case 1:
    out.push("new game");
    break;
  case 2:
    out.push("quit");
    break;
  default:
    out.push("unknown option");
}

console.log(out.join("\n"));
unknown option

Input 1-এর জন্য কোনো error নেই, অথচ ভুল branch চলে। next() দেয় string "1", আর "1" === 1 হলো false। nextInt() দিয়ে পড়ো, অথবা লেখো case "1":। ভুলটা হবে, কারণ == হলে মিলে যেত, আর switch কখনো == ব্যবহার করে না।

৪. সাধারণ object-এর উপর for...of।

const week = { mon: 7500, tue: 8000 };
for (const steps of week) {
  console.log(steps);
}
TypeError: week is not iterable

Iterable মানে "নিজের value-গুলো একটা একটা করে দিতে পারে", যেমন array আর string পারে। সাধারণ object পারে না, তাই প্রথম pass-এর আগেই loop throw করে। লেখো for (const day in week), আর পড়ো week[day]। ভুলটা হবে, কারণ for...of আর for...in-এ তফাত মাত্র দুইটা অক্ষরের।

মাথা খাটাও

একটা for loop-এর ভিতরে একটা switch, আর তার একটা case শেষ হয় break দিয়ে।

for (let i = 1; i <= 3; i++) {
  switch (i) {
    case 2:
      console.log("two, so break");
      break;
    default:
      console.log("pass", i);
  }
}
console.log("after the loop");

ওই break কি loop থেকে বের করে, নাকি শুধু switch থেকে? যে যে লাইন আসবে বলে মনে হয়, লিখে ফেলো, তারপর চালাও।

break-এর syntax card আবার পড়ো: ওই break-কে সবচেয়ে কাছ থেকে কোন statement ঘিরে আছে?

অনুশীলন ১সহজ

David 100 নম্বরের একটা class test-এর খাতা দেখে, আর প্রতিটা নম্বরকে একটা letter-এ বদলায়। কিছু নম্বর ভুল করে টাইপ হয়েছে, তাই 0 থেকে 100-এর বাইরের নম্বরের জন্য বলতে হবে invalid।

Input. n, তারপর n-টা পূর্ণসংখ্যা নম্বর।

Output. প্রতিটা নম্বরের জন্য এক লাইন। 90 থেকে 100 হলে A, 80 থেকে 89 হলে B, 70 থেকে 79 হলে C। 60 থেকে 69 হলে D, আর 0 থেকে 59 হলে F। 0-এর কম বা 100-এর বেশি নম্বর হলে invalid।

Constraints. 1 <= n <= 100000; -1000 <= mark <= 1000।

Sample. Input 7, তারপর 95 89 70 65 59 101 -1 দিলে সাত লাইনে A, B, C, D, F, invalid আর invalid।

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out

console.log(out.join("\n"));

letter-grade নামে grade হয়। Hidden test-গুলো সীমার প্রতিটা নম্বর দিয়ে চালায়, যেমন 89 আর 90, 0 আর 100, আর range-এর ঠিক বাইরের নম্বর।

Run in Compiler
অনুশীলন ২সহজ

Bob চায়, এবার ওর দিনের নামের switch-টা ঠিকঠাক চলুক। দিনগুলোর নম্বর 1 (Monday) থেকে 7 (Sunday), আর weekend-এর দুই দিন যেন একটাই body ভাগ করে।

Input. n, তারপর n-টা পূর্ণসংখ্যা।

Output. প্রতিটা সংখ্যার জন্য এক লাইন: দিনের ইংরেজি নাম, একটা space, তারপর weekday (1 থেকে 5) অথবা weekend (6 আর 7); অন্য যেকোনো সংখ্যার জন্য invalid। নামগুলো Monday, Tuesday, Wednesday, Thursday, Friday, Saturday আর Sunday।

Constraints. 1 <= n <= 100000; -1000 <= প্রতিটা সংখ্যা <= 1000।

Sample. Input 4, তারপর 1 6 7 9 দিলে চার লাইনে Monday weekday, Saturday weekend, Sunday weekend আর invalid।

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out

console.log(out.join("\n"));

day-name নামে grade হয়। Hidden test-গুলো 1 থেকে 7-এর প্রতিটা দিন দিয়ে চালায়, সাথে 0, 8 আর negative সংখ্যা দিয়েও।

Run in Compiler
অনুশীলন ৩সহজ

Zara ওর দোকানে যত টাকা আসে আর যায়, সব সংখ্যা হিসেবে লিখে রাখে, আর দিন শেষ হলে লেখে 0। ও জানতে চায়, কয়টা entry লিখেছে আর সব মিলিয়ে যোগফল কত।

Input. Space বা line break দিয়ে আলাদা করা পূর্ণসংখ্যা। তালিকা শেষ হয় প্রথম 0-তে, আর সেই 0 তালিকার অংশ না; ওই 0-এর পরে যা আছে, সব বাদ। অন্তত একটা 0 সবসময় থাকে।

Output. দুই লাইন: প্রথম 0-এর আগে কয়টা সংখ্যা এসেছে, আর তাদের যোগফল।

Constraints. প্রথম 0-এর আগে বড়জোর 100000-টা সংখ্যা; প্রতিটা -1000000 থেকে 1000000-এর মধ্যে।

Sample. Input 5 -2 7 0 4 4 দিলে দুই লাইনে 3 আর 10।

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out

console.log(out.join("\n"));

sum-until-zero নামে grade হয়। Hidden test-গুলো একদম প্রথম সংখ্যাটাই 0, negative সংখ্যা, আর 0-এর পরের সংখ্যা দিয়ে চালায়।

Run in Compiler
অনুশীলন ৪মাঝারি

Alice একটা bus ride-এর জন্য playlist বানায়, ride-টা নির্দিষ্ট লম্বা। ও গানগুলো ক্রম ধরে বাজায়, তবে 300 সেকেন্ডের চেয়ে লম্বা গান বাদ দেয়। পরের গানটা বাজালে মোট সময় ride-এর দৈর্ঘ্য পেরিয়ে যাবে, এমন হলে ও থেমে যায়, আর কিছুই বাজায় না।

Input. n আর ride-এর দৈর্ঘ্য L সেকেন্ডে, তারপর n-টা গানের দৈর্ঘ্য সেকেন্ডে।

Output. ক্রম ধরে প্রতিটা গান k-এর জন্য এক লাইন। 300-এর চেয়ে লম্বা গান হলে skip k। না হলে, মোট সময় আর এই গান মিলে L-এর বেশি হলে print করো stop at k, তারপর গানের আর কোনো লাইন না। না হলে print করো play k। সবশেষে print করো total, একটা space আর মোট বাজানো সেকেন্ড।

Constraints. 1 <= n <= 1000; 1 <= L <= 100000; 1 <= প্রতিটা দৈর্ঘ্য <= 1000।

Sample. Input 5 600, তারপর 200 400 180 250 90 দিলে আসে play 1, skip 2, play 3, stop at 4 আর total 380। গান 4 বাজালে হতো 630, যেটা 600 পেরিয়ে যায়।

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out

console.log(out.join("\n"));

আলাদা করে grade হয় না। একটা continue আর একটা break ব্যবহার করো, আর এত ছোট একটা ride দিয়ে চালাও, যাতে প্রথম গানেই থামতে হয়।

Run in Compiler
অনুশীলন ৫কঠিন

Maria k জন বন্ধুর জন্য cinema-র seat book করবে, ওরা এক row-তে পাশাপাশি বসতে চায়। Hall-এ r-টা row, প্রতিটায় c-টা seat, প্রতিটা হয় খালি নয়তো নেওয়া। সামনের row থেকে আর বাঁয়ের seat থেকে খুঁজলে পাশাপাশি k-টা খালি seat-এর প্রথম block কোনটা, সেটা ও জানতে চায়।

Input. r, c আর k, তারপর r-টা লাইন, প্রতিটায় c-টা সংখ্যা: খালি seat হলে 0, নেওয়া হলে 1।

Output. এক লাইন: প্রথম block-এর row আর তার প্রথম seat, দুইটাই 1 থেকে গোনা, মাঝে একটা space। এমন block না থাকলে print করো no seats।

Constraints. 1 <= r, c <= 1000; 1 <= k <= c।

Sample. Input 3 5 3, তারপর row-গুলো 1 0 0 1 0, 0 1 0 0 0 আর 0 0 0 0 0 দিলে আসে 2 3: row 2, seat 3 থেকে 5।

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out

console.log(out.join("\n"));

আলাদা করে grade হয় না। পুরো hall জমিয়ে না রেখে seat ধরে ধরে পড়ো, আর প্রথম block পেলেই label দেওয়া একটা break দিয়ে দুইটা loop থেকেই বের হয়ে যাও।

Run in Compiler

সচরাচর যে প্রশ্নগুলো আসে

  • Switch-এর শেষ case-এও কি break লাগে?

    না, শেষের brace এমনিতেই run থামিয়ে দেয়। তবু অনেক team ওটা লিখে রাখে। তাহলে পরে নিচে কেউ নতুন case জুড়লে ভুল করে fall-through ঢুকে পড়ে না।

  • do...while আসলে কখন ঠিক loop?

    যখন test-এর কোনো মানে দাঁড়ানোর আগেই body-কে একবার চলতে হবে। প্রথম choice-এর আগে menu দেখানো, বা এমন সংখ্যার digit কাটা যেটা 0-ও হতে পারে, এগুলোই সাধারণ উদাহরণ। বাকি সব জায়গায় while loop পড়তে বেশি সহজ।

  • for (;;) কি bug?

    না, এটা ইচ্ছে করে "চিরকাল চলো" বলা একটা loop। এর ভিতরে একটা break (বা Module 5-এর return) লাগবেই, না হলে সত্যিই চিরকাল চলবে। while (true)-এর মানেও একই, আর অনেকের কাছে সেটা পড়তে সহজ লাগে।

  • Label কি goto-র মতো?

    না। JavaScript-এ goto নেই। Label ব্যবহার করতে পারে শুধু break আর continue, আর শুধু তাদের ঘিরে থাকা একটা loop থেকে বের হতে বা সেটা আবার শুরু করতে। অন্য code-এর মাঝখানে লাফ দেওয়ার কোনো উপায় এতে নেই।

মূল কথা

  • else if chain-এ শুধু প্রথম truthy branch-টা চলে, তাই সবচেয়ে কড়া test-টা আগে বসাও।
  • switch মেলায় === দিয়ে, আর মিলে যাওয়া case থেকে নিচে একটা break পর্যন্ত চলে; খালি case সাজিয়ে রাখলে তারা একটা body ভাগ করে, আর ইচ্ছে করে গড়ানো case-এ থাকে // falls through comment।
  • n-টা pass-এর জন্য while loop test করে n + 1 বার, আর body একবারও না চলতে পারে; do...while body অন্তত একবার চালায়।
  • For loop-এর অংশগুলো খালি রাখা যায়, আর for (;;) চলে একটা break না আসা পর্যন্ত; for...of দেয় value, for...in দেয় key, string হিসেবে।
  • break বের হয় সবচেয়ে ভিতরের loop বা switch থেকে, continue চলে যায় পরের pass-এ, আর label থাকলে দুইটাই বাইরের loop পর্যন্ত পৌঁছাতে পারে।
  • আরও গভীরে: CP আর Interview Pack, nested loop, আগেভাগে বের হওয়া আর bug gallery (Pro)।

এরপর lesson 03 এই statement-গুলো কাজে লাগাবে সাতটা পুরো program-এ, FizzBuzz থেকে prime sieve পর্যন্ত।

lesson ২ শেষ

শেষ হলে চিহ্ন দিন, অগ্রগতি আপনার সাথে থাকবে।

পরেরটা: পুরো program: FizzBuzz থেকে prime sieve

প্রতিটা statement, একটা একটা করে | Learn JavaScript | Progsity