নিত্যদিনের জাভাস্ক্রিপ্টঃ map(), filter() ও reduce()

আমি আজকে নিত্যদিনের জাভাস্ক্রিপ্ট হিসেবে তিনটা মেথডের কথা আলোচনা করবো। এখনকার সময়ে আমার মনে হয় এই তিনটা মেথড সবচেয়ে বেশী ব্যবহৃত হয়। তাই ভাবলাম আমি এই তিনটা নিয়ে আলোচনা করি সবার সাথে।

এখানে তিনটা মেথডের কাজ প্রায় একই টাইপের। এরা Arrayর মেথড, এদের মেইন কাজ হলো অ্যাপ্লাইকৃত অ্যারের প্রত্যেকটা আইটেমের উপর একটা ফাংশন অ্যাপ্লাই করা। অনেকটা লুপের মতো কাজ করে, কিন্তু লুপের মতো অর্থহীন বা জটিল টাইপের না। প্রথমে বুঝতে হয়তো একটু সমস্যা হতে পারে। তবে একবার বুঝে গেলে তখন মনে হবে এগুলাই সবচেয়ে বেস্ট। এরা ফাংশনাল প্রোগ্রামিং এর অন্যতম উদাহরণ। আমি ফাংশনাল প্রোগ্রামিং নিয়ে আগে লিখেছি। চাইল সেটা পড়তে পারেন।

আপনি যদি ক্রোমের কন্সোলে লিখেনঃ

Array()

এখন __proto__ এর ভিতরে দেখলে এই তিনটা মেথড খুঁজে পাবেনঃ

এখানে উল্লেখিত মেথডগুলোর মধ্যে map() আর reduce() প্রথম আর্গুমেন্ট হিসেবে একটা কলব্যাক ফাংশন আর দ্বিতীয় আর্গুমেন্ট হিসেবে এই কলব্যাক ফাংশনের ভিতরে this এর ভ্যালু কি হবে সেটা সেট করা যায়। যেমন map() এর ক্ষেত্রেঃ

anArray.map(callbackFunction, thisArg);

তবে মনে রাখবেন এখানে this এর ভ্যালু ডিটারমাইন করা আর্গুমেন্টটা অ্যারো ফাংশনে অ্যারো ফাংশনের লেক্সিক্যাল this কীওয়ার্ডের এর কারণে একটু অন্যরকমভাবে কাজ করবে। এটা খুব বেশী কাজে লাগে না, তবে এরকম কিছু একটা আছে জেনে রাখা ভালো। আমি এটা নিয়ে শেষের দিকে আলোচনা করবো।

map():

আপনি map() কোনো অ্যারেতে কল করলে সেটা সেই অ্যারের প্রত্যেকটা আইটেমের উপর আপনারই দেওয়া একটা ফাংশন অ্যাপ্লাই করবে, এবং সবশেষে সবগুলো আবার আরেকটা অ্যারে হিসেবে রিটার্ন করবে।

ধরুন আপনার কাছে একটা অ্যারে আছেঃ

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

এখন এই অ্যারের প্রত্যেকটা আইটেমের স্কয়ার বের করতে চান। তাহলে আপনি যে যেটা করতে পারেনঃ

var anotherArr = []

for(var i = 0; i < arr.length; i++) {
   anotherArr.push(arr[i] * arr[i])
}

এখন anotherArr তে আপনার কাঙ্খিত রেজাল্ট পাবেন। কিন্তু যদি এটাও সঠিক, তারপরেও এখানে দেখুন আমাদের নতুন একটা অ্যারে নিতে হয়েছে। আবার আরেকটা মেথড push ইউজ করতে হয়েছে। আর for এর ভিতরে আরো কতো কিছু ইউজ করতে হচ্ছে যেগুলো আসলে মিনিংলেস। কোনো অর্থই নেই। সেইম কাজটাই আপনি যদি ম্যাপ এর মাধম্যে করতে চান। প্রথমে যে ফাংশন টা আপনার প্রত্যেকটা আইটেমের উপর অ্যাপ্লাই করতে চান। আপনি চান প্রত্যেকটা আইটেমের স্কয়ারঃ

function getSquare(item) {
   return item * item
}

এখন এই ফাংশনটা আপনার অ্যারের প্রত্যেকটা আইটেমে অ্যাপ্লাই করতে চান। এখানেই আসে map()

arr.map(getSquare)

এখন আমরা জানি এটাও একটা অ্যারে রিটার্ন করে। এখন সেই অ্যারেটা কোথাও স্টোর করতে হবেঃ

var newArr = arr.map(getSquare);

ফলাফল দেখুনঃ

এখন পুরোটাকে এভাবেও লেখা যাবেঃ

var newArr = arr.map(function(item) {
   return item * item;
})

এই পুরোটা সেইম আগের মতোই রেজাল্ট দিবে

এখন এখানে দেখবেন আমরা আর্গুমেন্ট হিসেবে একটা item ইউজ করেছি। কিন্তু এখানে map() তিনটা আর্গুমেন্ট অ্যাক্সেপ্ট করে। প্রথমটা তো দেখলামি, এটা অ্যারের প্রত্যেকটা আইটেম রিপ্রেজেন্ট করে, দ্বিতীয় আর্গুমেন্ট হচ্ছে অ্যারের আইটেমের ইন্ডেক্স নাম্বার, আর তৃতীয় নাম্বার টা সবসময়ই পুরো অ্যারে দিবে।

var newArr = arr.map(function(item, index, fullArr) {
    console.log('Item: ' + item + ' and index: ' + index + '. Full Array: ' + fullArr)
})

রেজাল্টঃ

আর যদি ES6 সিনট্যাক্স ইউজ করেন তাহলে সেটা কিরকম হয় দেখুনঃ

const newArr = arr.map(item => item * item);

এটা সেইম রেজাল্টই দেখাবে। কতো টা কম্প্যাক আর সুন্দর দেখুন।

filter():

ফিল্টার সেইম ম্যাপের মতোই কিন্তু এখানে অ্যাপ্লাইকৃত ফাংশন যদি true রিটার্ণ করে তাহলেই সেটা নতুন অ্যারেতে স্থান পাবে, নতুবা যদি ফাংশন false রিটার্ণ করে তাহলে সেই আইটেম অ্যারেতে স্থান পাবে না।

ধরুন আমি নিচের অ্যারে থেকে শুধুমাত্র জোড় নাম্বার গুলো বের করে নতুন অ্যারেতে রাখতে চাচ্ছিঃ

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]

এখন ফিল্টার মেথড অ্যাপ্লাই করে সেটা ইজিলিই করতে পারিঃ

var newArr = arr.filter(function(item) {
   return item % 2 == 0
})

প্রত্যেকটা আইটেমের উপর ফাংশন টা অ্যপ্লাই করা হয়েছে। এবং যেটা এখানে true রিটার্ণ করেছে, সেটাই নতুন অ্যারেতে স্থান পেয়েছে। আর যেটা false রিটার্ণ করেছে সেটা নতুন অ্যারেতে স্থান পায় নি।

এখানেও আপনি চাইলে অ্যানিনোমাস ফাংশন বা বাইরে ফাংশন নিয়ে এখানে কল করতে পারবেন ম্যাপের মতোই। রেজাল্ট দেখুনঃ

newArr

ফিল্টারও ম্যাপের মতোই তিনটা আর্গুমেন্ট অ্যাক্সেপ্ট করেঃ

ES6 সিনট্যাক্স ইউজ করলেঃ

const newArr = arr.filter(item => item % 2 === 0);

reduce():

রিডিউস ও ম্যাপ, ফিল্টার এর মতো হলেও এটা একটা আর্গুমেন্ট বেশী নেয়। আমরা প্রোগ্রামিং ওয়ার্ল্ড এ স্ট্যাট ভ্যারিয়েবলের কথা জানি। এর কাজ হচ্ছে কোনো কিছুর কাউন্ট করা, বা ডিটেক্ট করে রাখা কোনো অপারেশনের চলার সময়। সহজ কথায় বললে আমরা যদি কোনো অ্যারে থেকে অ্যারের সব নাম্বারের টোটাল বের চাই, তাহলে সেক্ষেত্রে রিডিউস ইউজ করে সহজেই করে ফেলতে পারি। রিডিউসে যেহেতু স্ট্যাট ভ্যারিয়েবল আছে, তাই এটাই এধরণের অপারেশনের জন্য পার্ফেক্ট চয়েজ হতে পারে।

ধরি অ্যারেঃ

var arr = [1, 2, 3, 4]

সব আইটেমের টুটাল জানতে চাই। রিডিউস অ্যাপ্লাই করলেঃ

var total = arr.reduce(function(sum, item){
   return sum += item;
}, 0);

এখন এটার রেজাল্ট আসবেঃ

এখানে অনেককিছু নতুন দেখা যাচ্ছে। হ্যা, এটা শুধুমাত্র একটা আর্গুমেন্ট শুরুর দিক হতে বেশী নিচ্ছে। যেটা হচ্ছে স্ট্যাট ভ্যারিয়েবল। আর একদম শেষে সেই স্ট্যাট ভ্যারিয়েবলের ইনিশিয়াল ভ্যালু কতো হবে সেটা সেট করে দিতে পারবেন। আমার ক্ষেত্রে জিরো দিয়েছি। আপনি ১০ দিলে ১০ থেকে শুরু হতো। রেজাল্ট আসতো ২০। আর সবশেষে এই মেথড আপনার টুটাল রিটার্ণ করতেছে, অন্যগুলোর মতো অ্যারে না, বরং টুটালটাই রিটার্ণ করবে।

তবে রিডিউসের মেইন কাজ হচ্ছে সবগুলো আইটেম নিয়ে আপনার দেওয়া ফাংশন অ্যাপ্লাই করে একটা সিঙ্গেল ভ্যালু রিটার্ণ করা। আমি এখানে টুটাল এক্সাম্পল হিসেবে নিলেও এর আরো অনেকরকম ইউজ কেস আছে। তবে মেইন কাজ একটাই একটা সিঙ্গেল ভ্যালু রিটার্ণ করবে।

আর বাকি সব অন্যান্য দুইটার মতোইঃ

var total = arr.reduce(function(sum, item, index, fullArr) {
   console.log('Item: ' + item + ' and index: ' + index + '. Full Array: ' + fullArr + ' and sum: ' + sum);
   return sum += item
}, 0)

রেজাল্টঃ

ES6 সিনট্যাক্স ইউজ করলেঃ

const t = arr.reduce((sum, item) => sum += item, 0)

this এর ভ্যালু ডিটারমাইন করাঃ উপরের তিনটা মেথডের মধ্যে map() আর filter() এ আমরা চাইলে এদের কলব্যাক ফাংশনের ভিতরে this এর ভ্যালু কি হবে সেটা সেট করে দিতে পারি। এটা অপশনাল আর্গুমেন্ট, কিছু না দিলে যেটা আমরা উপরে করেছি, this তার বাই ডিফল্ট বিহ্যেভিয়ারই দেখাবে। দুইটা মেথডেই এটা একইরকমভাবে কাজ করে। আর তাই আমি শুধুমাত্র map() দিয়ে উদাহরণ দেখাবো। ধরি আমাদের একটা অবজেক্ট আছে এরকমঃ

const anObj = {
   name: 'Zawad Ahmed',
   age: 1
}

এখন ধরি আমরা একটা অ্যারের উপর কিছু অপারেশন করবো। আমি ব্যাসিক একটা অ্যারে নিলামঃ

const anoArray = [1, 2, 4, 5, 6, 7, 9, 3];

এখন এটার উপর map() চালাবো, তবে জাস্ট this এর ভ্যালু কি আসে সেটা দেখার জন্যেঃ

anoArray.map(function(single, index, fullArr) {
   console.log(this)
})

এটা কন্সোলে রান করলেঃ

পরিষ্কারভাবেই এখানে this গ্লোবাল অবজেক্ট বা window কেই ইন্ডিকেট করছে। এখন আমরা আমাদের this এর ভ্যালু ডিটারমাইন করতে পারে সেই আর্গুমেন্টটা ইউজ করবো আর this এর ভ্যালু হিসেবে আমাদের বানানো anObj অবজেক্টটাকে ইউজ করবোঃ

anoArray.map(function(single, index, fullArr) {
   console.log(this)
}, anObj)

এটা রান করে এবার কন্সোলে দেখুনঃ

আমরা আমাদের কলব্যাক ফাংশনের ভিতরে this এর ভ্যালুই চেঞ্জ করে ফেলেছি।

এখন সেইম কাজটাই অ্যারো ফাংশনের ক্ষেত্রে আবার কাজ করবে না। কারণ অ্যারো ফাংশনে লেক্সিক্যাল this কীওয়ার্ড রয়েছে। যেটা আমরা অ্যারো ফাংশনের লেখায় বলেছিলাম।

এখানে উল্লেখিত উদাহরণ ছাড়াও আরো অনেক জায়গায় অনেকভাবে এই তিনটা মেথড ইউজ করা হয়। বিশ্বাস করুন এগুলো জাভাস্ক্রিপ্ট এর মধ্যে সবচেয়ে ইউজফুল মেথড আমার মতে। আমি শুধুমাত্র ব্যাসিকটা দিলাম। কারণ ব্যাসিক ক্লিয়ার থাকলে পরে যেকোন পরিস্থিতিতেই এগুলো ইউজ করতে পারবেন।

শেয়ার করুন

লেখাটি ভাল লাগলে সোশ্যাল মিডিয়ায় শেয়ার করুন। আপনার কলিগ, বন্ধু কিংবা প্রিয় কারও কাজে লাগতে পারে। জানেন তো, শেয়ারিং ইজ কেয়ারিং!

সাবস্ক্রিপশন সেন্টার

প্রতিদিন ওয়েবসাইটে আসা আপনার জন্য কষ্টকর হতে পারে। তাই যখনই আমি নতুন ব্লগ পোস্ট, সিরিজ, বই বা ভিডিও পাবলিশ করব,
তখনই তা আপনার ইমেইলে পেতে সাবস্ক্রাইব করুন। নো স্প্যামিং প্রমিজ!