Reduce করে একটা করে দাও (advanced)

এই map, forEach, filter, find-এর ক্যাটাগরিতে হালকা ভেজাইল্লা জিনিস হচ্ছে reduce। রিডিউস মানে কমানো। এইখানে রিডিউস বলতে বুঝায় একটা অ্যারের অনেকগুলা উপাদানকে কমিয়ে কমিয়ে একটা জিনিসে বা একটা মানে নিয়ে আসার সিস্টেম। এটাতে একটু ভেজাল আছে। তাই আমি নিজেও মাঝেমধ্যে গুলিয়ে ফেলি। আর গুলিয়ে ফেললে আবার খুঁজে বের করে দেখার চেষ্টা করি। আসলে মাঝেমধ্যে দুইটা-একটা হালকা ভেজাইল্লা জিনিস দেখার দরকার আছে। তাহলে শরীরে একটা ঝাঁকি পড়ে।
রিডিউস দেখার আগে সিম্পল একটা কোড দেখে আসি।
আমার কাছে কয়েকটা সংখ্যার একটা array আছে। এইটার সব সংখ্যার যোগফল বের করার কাজ আমরা খুব সহজেই বের করে ফেলতে পারি।
const numbers = [4, 5, 7, 1, 2, 66];
let sum = 0;
for (const num of numbers){
sum = sum + num
}
console.log(sum)
Output: 85এই কাজটাই reduce করলে এক লাইনে করা যায়। তবে এক লাইনে করতেই হবে। আর না করলে তুই প্রোগ্রামার হতে পারবি না, সেটা কিন্তু না। মেইন বিষয় হচ্ছে, তুই যদি শুরুর দিকে কোড করতে গিয়ে কয়েক লাইন বেশি কোড লিখে ফেলস, সেটা শুরুর দিকে বেশি দোষের না; বরং করতে করতে একসময় তুই নিজেও কিন্তু একসময় পেকে যাবি। তখন এইটাও একদিন তোর কাজে ইজি-পিজি, লেমন-চিজি মনে হবে। জাস্ট ধৈর্য ধরে চালিয়ে যেতে হবে। আর কিছু না।
তবে reduce দেখার যেহেতু নিয়ত আছে, তাই আগে একটু syntax দেখে বুঝার চেষ্টা কর। হাই লেভেলে দেখলে দুইটা জিনিস লাগবে।
arrayName.reduce (callbackFunction, initialValue)তারমানে একটা array-এর নামের পর ডট চিহ্ন দিয়ে reduce লিখবি, তারপর দুইটা জিনিস লাগবে। একটা কলব্যাক ফাংশন, আরেকটা হচ্ছে প্রাথমিক মান বা ইনিশিয়াল ভ্যালু। কলব্যাক ফাংশন জিনিসটা আমি একটু পরে আরো বিস্তারিত ডিসকাস করতেছি।
ওপরের কোডের দিকে তাকালে দেখতে পাবি। ওপরে sum নামে একটা ভেরিয়েবলের প্রাথমিক মান বা ভ্যালু দেয়া আছে, সেটাই এইখানে initialValue হিসেবে হবে। ওপরে যেমন 0 দেয়া আছে। এইখানেও সেইম কাজ করতে গেলে 0 প্রাথমিক মান হিসেবে আসবে। অন্য কিছু করতে গেলে সেই অনুসারে প্রাথমিক মান আসবে।
আর callBack ফাংশনটা অনেকটা map-এর ভিতরে ফাংশনের কাছাকাছি। এখন ওপরের কোডে for of লুপ এবং লুপের ভিতরের কাজগুলা দেখ।
for (const num of numbers){
sum = sum + num
}এই কোডের মধ্যে কী হচ্ছে? এইখানে একটা লুপ চলতেছে, আর লুপ চলার জন্য একটা একটা করে উপাদান আসতেছে। তারপর আগের একটা sum ডিক্লেয়ার করা ছিল, সেটার মধ্যে লুপ ভ্যারিয়েবল num-এর যোগ করতেছে। কাজ কিন্তু এইটাই। এইটাকে একটু গুছিয়ে বললে সাধারণভাবে বলা যায়।
(accumulator, currentValue) => doSomeWorkবা আমাদের উদাহরণের সাথে মিলিয়ে বললে বলা যায়—
(accumulator, currentValue) => accumulator + currentValueঅর্থাৎ দুইটা প্যারামিটারওয়ালা একটা অ্যারো ফাংশন আসবে। সেটার মধ্যে আগের মান প্রথম প্যারামিটার হিসেবে থাকবে (sum-এর কথা চিন্তা করতে পারস), তারপর সেকেন্ড প্যারামিটার হবে লুপ চললে প্রত্যেকবার নতুন যে উপাদান আসবে (num-এর কথা চিন্তা করতে পারস) সেটা। তারপর অ্যারো ফাংশনের ভিতরে আমরা কোনো একটা কাজ করব। এইখানে sum-এর সাথে num-এর যোগ করার মতো করে চিন্তা করলে accumulator-এর সাথে currentValue যোগ করতেছস। আর accumulator একটা কঠিন শব্দ, এইটার মানে একসাথে রাখা বা একসাথে বানানো বা যোগ করাও চিন্তা করতে পারস।
কিছুটা আইডিয়া পাইছস। এখন কলব্যাক ফাংশনকে একসাথে দেখলে একটু ভেজাইল্লা লাগবে। তাও এক চোখ বন্ধ করে দেখে ফেল। কী আছে জীবনে?
numbers.reduce((accumulator, currentValue) => doSomeWork, initialValue)আবারো বলতেছি, Reduce দুইটা প্যারামিটার নেয়। প্রথমটা হইতেছে একটা callback function, আর দ্বিতীয়টা হইতেছে initial value। আর আমাদের যে callback function আছে, তার ভিতরে আরও দুইটা প্যারামিটার থাকবে— একটা accumulator, আর অন্যটা current value।
তুই জানস, লুপ চলতে চলতে এক একটা করে উপাদান আসবে। এইখানে লুপ চলতে চলতে যখন যে উপাদানটা একটা ভেরিয়েবলের নাম দিয়ে আসবে, সেটাই থাকবে currentValue-এর মান হিসেবে। আরও সিম্পলভাবে বললে, লুপের মধ্যে num হিসেবে যেটা দেখছিলি, সেটাই আসলে currentValue, আর কিছু না।
অন্যদিকে accumulator হচ্ছে, লুপ চলতে চলতে কিছু কাজ (doSomeWork) করার পর যে রেজাল্ট হবে, সেই রেজাল্ট লুপের মধ্যে প্রত্যেকবার আসবে accumulator-এর মান হিসেবে।
তাইলে doSomeWork দিয়ে বুঝা যায় যে, লুপ চলতে চলতে প্রত্যেকবার কাজটা বারবার করবে।
আর initialValue হচ্ছে, ফাইনাল যে কাজটা করবে, সেটা লুপ শুরু হওয়ার আগে কত মান থাকবে। প্রাথমিক মান চিন্তা করতে পারস।
এত এত বিশাল ইতিহাস দেখার পর এইবার ছোট করে একটা উদাহরণ দেখে ফেল।
const numbers = [4, 5, 7, 1, 2, 66];
const total = numbers.reduce((sum, num) => sum + num, 0);
console.log(total);
Output: 85একটু ভেজাল হলেও জেনে রাখা ভালো।
const numbers = [32, 34, 73, 13, 22, 5];
const total = numbers.reduce((p, c) => p + c, 0);
console.log(total);
Output: 179এতক্ষণ যা শিখলি, map, forEach, filter, find, reduce— এইগুলা সিম্পল সংখ্যা বা স্ট্রিংয়ের জন্য ইউজ করছস। এখন সিম্পল সংখ্যার জন্য না করে অনেকগুলা অবজেক্টের একটা অ্যারের জন্য করে ফেল। অনেকটা সেইম জিনিসই। জাস্ট আগে map ফিল্টারের ভিতরে সরাসরি উপাদান পাইতি, এখন অবজেক্ট পাবি। আর অবজেক্ট থেকে প্রোপার্টির মান এক্সেস করার জন্য ডট নোটেশন বা বক্স নোটেশন ইউজ করবি, আর কিছু না।
আমাদের কাছে একটা অ্যারের মধ্যে বেশ কিছু object আছে।
const products = [
{id: 1, name: 'lenovo', price: 65000},
{id: 2, name: 'dell', price: 45000},
{id: 3, name: 'hp', price: 40000},
{id: 4, name: 'mac', price: 165000},
];আমি যদি শুধু প্রোডাক্টগুলার নাম পেতে চাই। খুবই সিম্পল।
const names = products.map(p => p.name);
console.log(names);
Output: [ 'lenovo', 'dell', 'hp', 'mac' ]তুই চাইলে এই একই সিস্টেমে সবগুলার দাম বা সবগুলার আইডি বা অন্য কোনো প্রোপার্টির মান একটা অ্যারের মধ্যে রেখে দিতে পারবি।
এইবার তুই যদি ঐসব প্রোডাক্টগুলো পেতে চাস, যেগুলার দাম 50 হাজার টাকার ওপরে। খুব সহজেই ফিল্টার করতে পারবি।
const expensive = products.filter(p => p.price > 50000);
console.log(expensive);
Output:
[
{ id: 1, name: 'lenovo', price: 65000 },
{ id: 4, name: 'mac', price: 165000 }
]আবার যদি 50 হাজার টাকার নিচে কোনো একটা প্রোডাক্ট হলেই হবে, তাহলে তুই ফাইন্ড ইউজ করে ফেলতে পারবি। তোকে রিটার্ন হিসেবে সেই উপাদান বা সেই অবজেক্টটা দিয়ে দিবে।
const affordable = products.find(p => p.price < 50000);
console.log(affordable);
Output:
{ id: 2, name: 'dell', price: 45000 }আবার তুই যদি সবগুলা প্রোডাক্টের দামের যোগফল পেতে চাস, তাহলে তুই তোর প্রিয় reduce ইউজ করে ফেলতে পারবি।
const total = products.reduce((accumolator, current) => accumolator + current.price, 0);
console.log(total);
Output: 315000
Practice:
- তোর কাছে একটা array আছে: [5, 10, 15, 20, 25]। তুই একটা প্রোগ্রাম লিখে দেখ, সব সংখ্যার যোগফল কত হয় reduce দিয়ে।
- তুই একটা দোকানের মালিক। তোর পণ্যগুলা: [{name: 'shampoo', price: 100}, {name: 'soap', price: 50}, {name: 'toothpaste', price: 75}]। সব পণ্যের মোট দাম বের কর reduce ব্যবহার করে।
- ধর, তুই একটা product-এর list বানাইছিস: [{name: 'Pen', price: 5}, {name: 'Book', price: 50}, {name: 'Bag', price: 100}]। এবার সব পণ্যের দাম যোগ কর reduce দিয়ে।
- reduce দিয়ে [1, 2, 3, 4, 5] সব সংখ্যার গুণফল বের কর।
- [10, 20, 30, 40, 50] এই অ্যারে reduce ব্যবহার করে সর্বোচ্চ মান বের কর।
- একটা অ্যারে বানা [100, 200, 300, 400]। reduce দিয়ে সব সংখ্যার যোগফল বের কর এবং ইনিশিয়াল ভ্যালু হিসেবে 50 ব্যবহার কর।