Learn JavaScript

lesson ৪ / ৯ · if, switch আর loop

Module ৪ · if, switch আর loop

কোন loop, আর কখন if-এর চেয়ে switch ভালো

Freeপড়া

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

  • তিনটা প্রশ্ন দিয়ে loop বেছে নিতে পারবে: কতবার চলবে আগে থেকে জানো কিনা, প্রতিটা item-এর উপর দিয়ে হাঁটছ কিনা, আর test-এর আগে body-কে একবার চলতেই হবে কিনা।
  • For loop, while loop, do...while, for...of, for...in আর forEach-কে এক chart-এ মিলিয়ে দেখতে পারবে, আর একটা if chain, একটা switch আর একটা lookup object-এর মধ্যে বেছে নিতে পারবে।
  • উত্তর জানা মাত্রই break দিয়ে loop থামাতে পারবে, আর বুঝিয়ে বলতে পারবে forEach কেন পারে না।

Amara-র code সারাদিনের order-গুলো দেখে, আর 1000-এর বেশি প্রথম order-টাকে দাগিয়ে দেয়। ওর loop ঠিক ওই order-এ এসে break দিয়ে থেমে যায়। Kenji review করে একটাই comment লেখে: "use forEach everywhere"। শুনতে পরিপাটি, কিন্তু forEach-এর থামার কোনো উপায় নেই, তাই ওর version প্রতিটা order পড়বে, আর ভুল order-টাকেও দাগাতে পারে। দুজনেই loop চেনে। ওদের যেটা নেই, সেটা বেছে নেওয়ার একটা উপায়, আর এই lesson সেটাই বানায়।

তিনটা প্রশ্নেই loop বাছাই

JavaScript-এ রোজকার loop statement পাঁচটা, সাথে forEach method, আর বেশিরভাগ কাজ একাধিকটা দিয়েই হয়। তিনটা প্রশ্নে ব্যাপারটা মিটে যায়। ক্রম ধরে জিজ্ঞেস করো, প্রথম হ্যাঁ-তেই থামো।

কোন loop: সিদ্ধান্তের flowchart তিনটা প্রশ্নেই loop বাছাই 1. একটা array বা string-এর প্রতিটা item-এর উপর দিয়ে? হ্যাঁ for...of value দেয়, position দেয় না না 2. শুরুর আগেই কি জানো কতবার? হ্যাঁ for loop for (let i = 0; i < n; i++) না 3. প্রথম test-এর আগে body-কে কি একবার চলতেই হবে? হ্যাঁ do...while আগে body, তারপর test না while loop কিছু একটা না বদলানো পর্যন্ত, যেমন input শেষ হওয়া একটা object-এর key? guard-সহ for...in। Object.keys আনবে Module 8। এই chart-এর প্রতিটা loop break দিয়ে আগেভাগে থামতে পারে। forEach পারে না।

প্রশ্নগুলো সবচেয়ে নির্দিষ্ট থেকে সবচেয়ে সাধারণের দিকে যায়। তুমি একটা তালিকার উপর দিয়ে হাঁটলে for...of এক লাইনেই সেটা বলে দেয়। কতবার, সেটা জানা থাকলে for loop শুরু, test আর step এক জায়গায় রাখে। দুটোর কোনোটাই না খাটলে তবেই while loop লাগে, আর do...while সেই বিরল case, যেটাকে একবার চলতেই হবে। তাই flowchart সবসময় গিয়ে থামে সেই loop-এ, যেটা তোমার উদ্দেশ্যটা সবচেয়ে বেশি করে বলে।

ছয়টা loop, এক chart-এ

Flowchart একটা কাজের জন্য loop বেছে দেয়। নিচের chart বলে কোন loop কী পারে, যাতে তুমি নিজের বাছাইটা মিলিয়ে নিতে পারো। forEach আসলে statement না, প্রতিটা array-র একটা method, তাই ওটা শেখাবে Module 7; এখানে আছে কারণ Kenji ওটাই চেয়েছে।

LoopIndex আছে?break চলে?অন্তত একবার চলে?Array-তে চলে?Object-এর key-তে চলে?সাধারণ কাজ
for loopহ্যাঁ, তোমার বানানো counterহ্যাঁনাহ্যাঁ, index দিয়েনাজানা সংখ্যক বার, বা position লাগলে
while loopশুধু নিজে যেটা রাখোহ্যাঁনাহ্যাঁ, একটা counter দিয়েনাকিছু একটা না বদলানো পর্যন্ত চালাও
do...whileশুধু নিজে যেটা রাখোহ্যাঁহ্যাঁহ্যাঁ, একটা counter দিয়েনাএকবার করো, দরকার হলে আবার
for...ofনা, value দেয়হ্যাঁনাহ্যাঁ, এর value-গুলোনা, সাধারণ object iterable নাএকটা array বা string-এর প্রতিটা value
for...inkey দেয়, string হিসেবেহ্যাঁনাচলে, কিন্তু key-গুলো stringহ্যাঁএকটা object-এর key (Module 8)
forEachহ্যাঁ, দ্বিতীয় parameterনানাহ্যাঁনাপ্রতিটা item, মাঝপথে থামা নেই (Module 7)

আগে "break চলে?" কলামটা পড়ো: পাঁচটা হ্যাঁ, একটা না। তারপর "অন্তত একবার চলে?": শুধু do...while, কারণ সে test করে body-র পরে। Example 1 একই তালিকা ছয়টা loop দিয়েই চালায়।

এই lesson-এর নতুন দুইটা loop-এর গড়ন

do {
  body
} while (test);

array.forEach((item, index) => {
  body
});
  • do...while আগে body চালায়, তারপর test দেখে, আর test যতক্ষণ true ততক্ষণ আবার চালায়। শেষের semicolon-টা খেয়াল করো।
  • forEach প্রতিটা item-এর জন্য arrow function-টা একবার করে call করে, item আর তার index দিয়ে। Function বোঝাবে Module 5, আর method-টা Module 7।
  • ওই arrow function-এর ভিতরের return শুধু একটা call শেষ করে, loop না, আর সেখানে break লিখলে SyntaxError।
Example 1: এক তালিকা, ছয় loop

তিনটা দাম, ছয় ভাবে হাঁটা। prices.length মানে array-তে কয়টা item, আর prices[i] মানে i নম্বর position-এর item, গোনা শুরু 0 থেকে (Module 7)।

const prices = [120, 450, 1300];
const out = [];

let line = "for:";
for (let i = 0; i < prices.length; i++) {
  line += " " + i + "=" + prices[i];
}
out.push(line);

line = "while:";
let w = 0;
while (w < prices.length) {
  line += " " + prices[w];
  w++;
}
out.push(line);

line = "do...while:";
let d = 0;
do {
  line += " " + prices[d];
  d++;
} while (d < prices.length);
out.push(line);

line = "for...of:";
for (const price of prices) {
  line += " " + price;
}
out.push(line);

line = "for...in:";
for (const key in prices) {
  line += " " + key + " (" + typeof key + ")";
}
out.push(line);

line = "forEach:";
prices.forEach((price, index) => {
  line += " " + index + "=" + price;
});
out.push(line);

console.log(out.join("\n"));
for: 0=120 1=450 2=1300
while: 120 450 1300
do...while: 120 450 1300
for...of: 120 450 1300
for...in: 0 (string) 1 (string) 2 (string)
forEach: 0=120 1=450 2=1300

For loop আর forEach index হাতে তুলে দেয়; while loop দুটোতে index নিজেকে রাখতে হয়। সবচেয়ে ছোট for...of, কারণ কাজটাই "প্রতিটা value"। for...in দেয় key, আর typeof দেখায় প্রতিটা key একটা string, number না। এটা একটা যোগফলের কী দশা করে, দেখাবে common mistake 4।

Run in Compiler

এক সমস্যা, তিন উপায়: if, switch আর lookup

Kenji-র café-তে cup-এর মাপ তিনটা: S মানে 250 ml, M মানে 350 ml, L মানে 500 ml। একটা program মাপের code থেকে millilitre বের করে, আর বাকি সবকিছুর জন্য বলে "unknown"। নিচে এই একটাই কাজ তিন ভাবে লেখা, একই পাঁচটা code-এর উপর। শেষ code-টা, constructor, হলো Zara-র edge case।

Example 2: if chain

প্রতিটা test একই value-কে একটা করে constant-এর সাথে মেলায়।

const out = [];
for (const size of ["S", "M", "L", "XL", "constructor"]) {
  let ml;
  if (size === "S") {
    ml = 250;
  } else if (size === "M") {
    ml = 350;
  } else if (size === "L") {
    ml = 500;
  } else {
    ml = "unknown";
  }
  out.push(size + ": " + ml);
}
console.log(out.join("\n"));
S: 250
M: 350
L: 500
XL: unknown
constructor: unknown

কাজ করে, কিন্তু size === লেখা হয়েছে তিনবার। গড়নটা বলছে "এক value, অনেক constant", আর switch ঠিক এই কাজের জন্যই।

Run in Compiler
Example 3: switch

Value-টার নাম আসে একবারই, আর প্রতিটা case-এ থাকে একটা constant।

const out = [];
for (const size of ["S", "M", "L", "XL", "constructor"]) {
  let ml;
  switch (size) {
    case "S":
      ml = 250;
      break;
    case "M":
      ml = 350;
      break;
    case "L":
      ml = 500;
      break;
    default:
      ml = "unknown";
  }
  out.push(size + ": " + ml);
}
console.log(out.join("\n"));
S: 250
M: 350
L: 500
XL: unknown
constructor: unknown

Output একই। পাঠক এক নজরেই দেখে, test হচ্ছে শুধু size। দাম দিতে হয় প্রতিটা case-এ একটা করে break, আর একটা বাদ পড়লেই আসল bug, সেজন্যই linter এদিকে নজর রাখে।

Run in Compiler
Example 4: lookup object

মাপ থেকে ml-এর জোড়াগুলো এবার data। { S: 250, M: 350, L: 500 } একটা object, মানে নাম দেওয়া কয়েকটা value-র একটা সেট, আর cupMl[size] পড়ে size যে নামটা বলে, সেই value; object শেখাবে Module 8। Object.hasOwn(cupMl, size) জিজ্ঞেস করে, নামটা object-এর নিজের কিনা।

const cupMl = { S: 250, M: 350, L: 500 };
const out = [];
for (const size of ["S", "M", "L", "XL", "constructor"]) {
  const ml = Object.hasOwn(cupMl, size) ? cupMl[size] : "unknown";
  out.push(size + ": " + ml);
}
console.log(out.join("\n"));
S: 250
M: 350
L: 500
XL: unknown
constructor: unknown

Loop-এর body এক লাইনের, আর নতুন একটা মাপ মানে আরেকটা entry, আরেকটা branch না। Guard-টা আছে Zara-র edge case-এর জন্য। প্রতিটা object prototype থেকে এমন কয়েকটা নাম inherit করে, যেগুলো সে কখনো লেখেনি, constructor তার একটা, তাই cupMl["constructor"] undefined-এর বদলে একটা function খুঁজে পায়। Object.hasOwn না থাকলে শেষ লাইনে print হতো constructor: function Object() { [native code] }।

Run in Compiler

তাহলে নিয়মটার তিন ভাগ। এক value-কে অনেকগুলো constant-এর সাথে মেলাতে switch। Range আর মিশ্র শর্তের জন্য if chain, যেমন t > 30, বা একসাথে দুইটা value। জোড়াগুলো যখন logic না হয়ে data, তখন lookup object, বিশেষ করে যদি তালিকাটা বাড়তে পারে বা কোনো settings file থেকে আসে।

জানা মাত্রই থামো

আগেভাগে বের হওয়া (early exit) মানে উত্তর জানার সাথে সাথে loop ছেড়ে দেওয়া। Lesson 03-এর prime check-এ এমন দুইটা আছে: প্রথম ভাজকেই break, আর d * d <= n test। প্রতিটা কতটা কাজ বাঁচায়, এখানে আন্দাজে না, গুনে দেখা।

Example 5: ভাগগুলো গোনা

দশ লাখের কাছাকাছি তিনটা সংখ্যা, প্রতিটা তিন ভাবে যাচাই। Counter-গুলো লিখে রাখে, কোন উপায়ে কয়টা ভাগ হলো।

const out = [];
for (const n of [999983, 999999, 1000000]) {
  let noBreak = 0;
  let isPrime = true;
  for (let d = 2; d < n; d++) {
    noBreak++;
    if (n % d === 0) {
      isPrime = false;
    }
  }

  let withBreak = 0;
  for (let d = 2; d < n; d++) {
    withBreak++;
    if (n % d === 0) {
      break;
    }
  }

  let withRoot = 0;
  for (let d = 2; d * d <= n; d++) {
    withRoot++;
    if (n % d === 0) {
      break;
    }
  }

  out.push(n + (isPrime ? " prime" : " composite") + ": no break " + noBreak + ", break " + withBreak + ", break and root " + withRoot);
}
console.log(out.join("\n"));
999983 prime: no break 999981, break 999981, break and root 998
999999 composite: no break 999997, break 2, break and root 2
1000000 composite: no break 999998, break 1, break and root 1

দুই রকম বের হওয়া দুই রকম সংখ্যার কাজে লাগে। Composite সংখ্যার বেলায় break প্রায় দশ লাখ ভাগকে নামিয়ে আনে এক-দুইটায়, কিন্তু prime-এর কোনো উপকার করতে পারে না, কারণ ওর খুঁজে পাওয়ার মতো কোনো ভাজকই নেই। বর্গমূলের test সাহায্য করে prime-কে: 999,981-এর জায়গায় 998টা ভাগ। দুটো মিলে দুই case-ই সামলায়, আর কোনোটাই উত্তর বদলায় না।

Run in Compiler

এবার Amara-র loop-এ ফিরি। উত্তর জানার পরেও Kenji-র forEach সব order-এর উপর দিয়ে হেঁটে যেত। break-সহ একটা for...of ঠিক ওখানেই থামে। Array-র find method-ও থামে, যেটা শেখাবে Module 7, আর method পছন্দ করা অনেক team এখানে ওটাই লিখত।

Example 6: সীমার উপরের প্রথম order

Amara-র loop, কতদূর পড়ল দেখাতে একটা counter-সহ, পাশে find।

const orders = [120, 450, 1300, 80, 2500, 60];
const limit = 1000;
const out = [];

let looked = 0;
let first;
for (const amount of orders) {
  looked++;
  if (amount > limit) {
    first = amount;
    break;
  }
}
out.push("for...of with break: " + first + ", looked at " + looked);

const found = orders.find((amount) => amount > limit);
out.push("find: " + found);

console.log(out.join("\n"));
for...of with break: 1300, looked at 3
find: 1300

Loop ছয়টা order-এর তিনটা পড়ে থেমে যায়। find ফেরত দেয় প্রথম সেই item, যার জন্য arrow function true বলে, আর সে-ও ওখানেই থামে। Kenji-র forEach version আর তার আসল output দেখাবে common mistake 2।

Run in Compiler

Style guide-এর নিজস্ব মত থাকে, আর তাতে সমস্যা নেই

একটা team নিজের অভ্যাসগুলো লিখে রাখে একটা style guide-এ, আর একটা linter সেগুলো মানতে বাধ্য করে। Airbnb JavaScript Style Guide-এর নিয়ম 11.1 বলে iterator ব্যবহার কোরো না, for...in আর for...of-এর বদলে array method বেছে নাও। ওদের ESLint configuration এটা চাপায় no-restricted-syntax দিয়ে, যেটা দুইটা loop-ই, labelled statement আর with নিষেধ করে। for...in-এর message সাবধান করে, এটা inherit করা key-গুলোর উপর দিয়েও যায়।

for...of-এর message দুইটা কারণ দেয়। পুরনো browser-এর জন্য compile করা code-এ একটা ভারী helper library লাগত, regenerator-runtime, আর guide এমনিতেও array method পছন্দ করে। প্রথম কারণটা Node 22-এ খাটে না, Node 22 for...of নিজেই চালায়। দ্বিতীয়টা team-এর রুচি, আর একটা team-এর রুচি থাকতেই পারে।

এই module-এর দুইটা ESLint নিয়ম মেনে নেওয়া সহজ। guard-for-in চায় প্রতিটা for...in-এর body একটা if দিয়ে key ছেঁকে নিক, সাধারণত Object.hasOwn দিয়ে, যাতে inherit করা key-গুলো বাদ পড়ে। no-fallthrough সেই case-কে ধরে, যেটা "falls through" লেখা কোনো comment ছাড়াই পরের case-এ গড়িয়ে পড়ে। Lesson 03-এর Kenji-র kiosk-এর মতো খালি, জোট-বাঁধা case-কে এটা ছাড় দেয়, আর নিয়মটা ESLint-এর recommended set-এ আছে।

তাই Airbnb-র মতো একটা নিয়ম ঠিকই আছে। সে একটু স্বাধীনতা ছেড়ে দিয়ে বদলে পায় এমন code, যেটা পুরো team জুড়ে একই রকম পড়া যায়। তোমার team for...of নিষেধ করলেও flowchart কাজ করবে: উত্তরটা তখন হবে find, some বা forEach, থামতে হবে কিনা সেটা দেখে বাছা।

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

  • Airbnb JavaScript Style Guide। ওদের iterator নিয়ম, 11.1, loop-এর চেয়ে array method পছন্দ করে, আর ওদের ESLint configuration no-restricted-syntax দিয়ে প্রতিটা for...in আর for...of-কে ধরে।
  • ESLint। guard-for-in নিয়ম একটা for...in-এর body-কে একটা if দিয়ে key ছেঁকে নিতে বাধ্য করে, যাতে object-এর শুধু inherit করা কোনো key loop-এ ঢুকে না পড়ে।
  • Fastify-র router। Fastify web framework-এর নিচের router find-my-way প্রতিটা HTTP method-এর জন্য একটা করে route tree রাখে একটা object-এ, this.trees[method]। মানে GET, POST আর বাকিগুলোর উপর একটা switch-এর জায়গায় একটা lookup object।

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

১. যে while loop আসলে for loop হওয়া উচিত ছিল।

const out = [];
let day = 1;
while (day <= 7) {
  out.push("day " + day);
  if (day === 5) {
    out.push("weekend next");
    day++;
  }
  day++;
}
console.log(out.join("\n"));
day 1
day 2
day 3
day 4
day 5
weekend next
day 7

কোনো error নেই, আর day 6 হাওয়া। Counter update হচ্ছে দুই জায়গায়, তাই day 5-এ সে দুইবার নড়ে। লেখো for (let day = 1; day <= 7; day++), আর body-তে day-কে কখনো ছুঁয়ো না। ভুলটা হয় যখন একটা while loop একটা একটা বিশেষ case যোগ হতে হতে বড় হয়।

২. return দিয়ে forEach থামানোর আশা।

const orders = [120, 450, 1300, 80, 2500, 60];
let looked = 0;
let first;
orders.forEach((amount) => {
  looked++;
  if (amount > 1000) {
    first = amount;
    return;
  }
});
console.log("first " + first + ", looked at " + looked);
first 2500, looked at 6

কোনো error নেই, আর উত্তরটা ভুল। return arrow function-এর একটা call শেষ করে, আর forEach পরের order-এর জন্য ওকে আবার call করে, তাই 2500 এসে 1300-কে মুছে দেয়। ওখানে break লিখলে আসে SyntaxError: Illegal break statement। break-সহ for...of লেখো, নয়তো find। তুমি ভাববে return থামিয়ে দেবে, কারণ শব্দটা শুনলেই মনে হয় "এখনই বেরোও"।

৩. Range-এর উপর switch।

const t = 34;
let label;
switch (t) {
  case t > 30:
    label = "hot";
    break;
  case t > 15:
    label = "mild";
    break;
  default:
    label = "cold";
}
console.log(t + " is " + label);
34 is cold

কোনো error নেই, আর কিছুই মেলে না। প্রতিটা case-এর হিসাব আগে হয়, তাই t > 30 হয়ে যায় true, আর switch জিজ্ঞেস করে 34 === true কিনা। Range-এর জায়গা if chain-এ। এটা তুমি চেষ্টা করবে, কারণ "if-এর চেয়ে switch ভালো" শুনে মনে হয়েছিল সব chain-এর জন্যই নিয়ম।

৪. for...of-এর জায়গায় for...in।

const scores = [10, 20, 30];
let total = 0;
for (const s in scores) {
  total += s;
}
console.log("total " + total);
total 0012

কোনো error নেই, আর total এখন text। for...in দেয় key, "0", "1" আর "2", score-গুলো না, আর 0 + "0" text জোড়া লাগায়। লেখো for (const s of scores)। দুটো গুলিয়ে ফেলবে, কারণ ইংরেজিতে "in" শুনলে মনে হয় "তালিকার ভিতরের প্রতিটা item"।

মাথা খাটাও

const tokens = [];
let at = 0;
let command = tokens[at++];
while (command !== undefined && command !== "quit") {
  console.log("menu: add, list, quit");
  command = tokens[at++];
}

Bob-এর tool-কে অন্তত একবার menu দেখাতে হবে, তারপর quit বা input শেষ না হওয়া পর্যন্ত command পড়তে হবে। এখানকার মতো খালি input-এ এটা কিছুই print করে না। Chart-এর কোন loop মাত্র একটা console.log লাইন দিয়ে এটা সারায়? তোমার সারানো version-এ token add, list, quit, add দিলে কয়বার menu print হয়?

Chart-এর "অন্তত একবার চলে?" কলামটা দেখো। তারপর হাতে হাতে trace করো: menu print হয়, একটা command পড়া হয়, আর তার পরেই কেবল test চলে।

অনুশীলন ১সহজ

লম্বা একটা আবহাওয়ার খাতা থেকে Zara চায় প্রথম সেই দিনটা, যেদিন তাপমাত্রা 0-এর নিচে নামে, আর তার পরে আর কিছু পড়তে চায় না।

Input. n, তারপর n-টা পূর্ণসংখ্যা, দিন 1 থেকে n-এর তাপমাত্রা।

Output. প্রথম যে দিনের তাপমাত্রা 0-এর নিচে, তার জন্য day d, আর এমন দিন না থাকলে none।

Constraints. 1 <= n <= 100000; -100 <= প্রতিটা তাপমাত্রা <= 100।

Sample. Input 6, তারপর 4 2 0 -3 5 -1 দিলে day 4।

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 হয় না। ঠিক 0 তাপমাত্রা 0-এর নিচে না, আর কোন loop দিয়ে শুরু করবে, সেটা flowchart-ই বলে দেয়।

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

Kenji-র দোকানের till input শেষ না হওয়া পর্যন্ত command পড়ে। sale x total-এ x যোগ করে, আর refund x x বাদ দেয়। total print করে total আর total-টা। close print করে closed আর total, তারপর run শেষ, তাই এর পরের প্রতিটা command উপেক্ষিত। অন্য যেকোনো শব্দ print করে unknown আর শব্দটা, আর তার পরে কোনো amount আসে না।

Input. Command-গুলো, space বা line break দিয়ে আলাদা, input শেষ না হওয়া পর্যন্ত।

Output. প্রতিটা total, close আর অচেনা শব্দের জন্য এক লাইন, উপরে যেমন বলা। close ছাড়াই input শেষ হলে সবশেষে print করো no close। Total শুরু হয় 0 থেকে, আর 0-এর নিচেও নামতে পারে।

Constraints. বড়জোর 100000টা command; প্রতিটা amount 1 থেকে 1000000-এর একটা পূর্ণসংখ্যা; command-এর শব্দে শুধু ছোট হাতের অক্ষর।

Sample. Input sale 250 sale 100 refund 50 total tip close sale 5 দিলে তিন লাইনে total 300, unknown tip আর closed 300।

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"));

till-commands নামে grade হয়। Hidden test-এ আছে close ছাড়া run, close-এর পরেও command, আর 0-এর নিচে নামা total।

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

Kenji-র cinema-র একটা seat map আছে: r সারিতে c-টা করে seat, ফাঁকা হলে 0, ভরা হলে 1। Alice সামনে থেকে সারি ধরে পড়ে প্রথম ফাঁকা seat-টা চায়। Kenji জানতে চায়, ওটা পেতে কয়টা seat দেখতে হলো।

Input. r আর c, তারপর r-টা লাইনে c-টা করে সংখ্যা, প্রতিটা 0 বা 1।

Output. দুইটা লাইন। প্রথমে প্রথম ফাঁকা seat-এর জন্য row R seat S, দুটোই 1 থেকে গোনা, আর একটাও না থাকলে full। তারপর checked K, মানে কয়টা seat দেখা হলো, ফাঁকাটাসহ।

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

Sample. Input 3 4, তারপর তিন লাইনে 1 1 1 1, 1 1 0 1 আর 0 0 0 0 দিলে row 2 seat 3 আর checked 7।

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 হয় না। দুইবার সমাধান করো: একবার nested loop আর lesson 02-এর labelled break দিয়ে, তারপর r গুণ c-টা seat-এর উপর একটাই loop দিয়ে। কোনটা পড়তে ভালো লাগে?

Run in Compiler

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

  • forEach কি for loop-এর চেয়ে ধীর?

    আবার Kenji-র প্রিয় প্রশ্ন। হতে পারে, আর lesson 05 আন্দাজ না করে Node 22-এ মেপে দেখায়। বেশিরভাগ code-এ পার্থক্যটা এত ছোট যে গায়ে লাগে না, তাই বেছে নাও থামতে হবে কিনা সেটা দেখে।

  • forEach-কে আগেভাগে থামানোর কি কোনো উপায়ই নেই?

    আছে শুধু ভিতর থেকে একটা error ছুড়ে দিয়ে, যেটা সাধারণ একটা খোঁজাকে error-এর পথে ঠেলে দেয়। থামার দরকার হলে কাজটা আর "প্রতিটা item" না, তাই break-সহ for...of লেখো, নয়তো find আর some।

  • Range test করতে কি switch (true) লিখতে পারি?

    চলে: প্রতিটা case t > 30 মেলানো হয় true-এর সাথে, তাই প্রথম true case-টাই জেতে। কিন্তু বেশিরভাগ পাঠক আশা করে একটা switch এক value-কে constant-এর সাথে মেলাবে। একটা if chain একই কথা বলে, কোনো কৌশল ছাড়াই।

  • সবসময় lookup object নিলেই তো হয়?

    Lookup এক value থেকে আরেক value-তে নিয়ে যায়। প্রতিটা case-কে যখন আলাদা কিছু করতে হয়, বা একটা range test করতে হয়, তখন logic-টার জায়গা if chain বা switch। Module 8 এমন lookup দেখাবে, যেগুলোর ভিতরে function থাকে, তাতে সীমারেখাটা একটু ঝাপসা হয়।

মূল কথা

  • তিনটা প্রশ্নে loop বাছাই: তালিকা মানে for...of, জানা সংখ্যক বার মানে for loop, "test-এর আগে একবার" মানে do...while, আর বাকি সব while loop।
  • প্রতিটা loop statement break করতে পারে; forEach পারে না, আর এর ভিতরের return শুধু একটা call শেষ করে।
  • for...in key দেয় string হিসেবে: guard-সহ একটা object-এর key-র জন্য ব্যবহার করো, array-র উপর দিয়ে হাঁটতে কখনো না।
  • এক value বনাম অনেক constant হলে switch, range হলে if chain, আর জোড়াগুলো data হলে lookup object।
  • উত্তর জানা মাত্রই বেরিয়ে যাও: মিলে গেলে কাজ বাঁচায় break, আর না মিললে বাঁচায় d * d <= n-এর মতো আঁটসাঁট একটা test।
  • আরও গভীরে: Under the Hood, jump দিয়ে loop, iterator protocol আর একটা loop lab (Pro)।

এরপর lesson 05 engine-এর ভিতরটা খোলে: bytecode-এ jump হিসেবে loop, for...of-এর পেছনের protocol, আর মাপা সংখ্যাসহ একটা loop lab।

lesson ৪ শেষ

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

পরেরটা: ভেতরের কথা: jump দিয়ে loop, iterator protocol আর একটা loop lab

কোন loop, আর কখন if-এর চেয়ে switch ভালো | Learn JavaScript | Progsity