স্কালাতে স্ট্রিম এবং লেজি কালেকশনস দুটি গুরুত্বপূর্ণ ফিচার যা ডেটা প্রক্রিয়াকরণের জন্য অত্যন্ত কার্যকরী। এগুলি লেজি (Lazy) বা অন-ডিমান্ড (on-demand) অপারেশন প্রক্রিয়া গ্রহণ করে, অর্থাৎ আপনার ডেটার সবগুলো উপাদান একসাথে লোড না করে শুধুমাত্র প্রয়োজনীয় উপাদানগুলি প্রক্রিয়া করা হয়।
১. স্ট্রিম (Streams)
স্ট্রিম হল একটি ধারাবাহিক ডেটা প্রবাহ, যা একটি ডেটা কালেকশন থেকে উপাদানগুলি একে একে পড়তে এবং প্রক্রিয়া করতে ব্যবহৃত হয়। স্কালাতে, স্ট্রিমগুলি মূলত লেজি কালেকশনস বা lazy evaluation এর সাথে সম্পর্কিত, যেখানে সমস্ত উপাদান একই সময়ে লোড বা প্রক্রিয়া করা হয় না। স্ট্রিমগুলির মধ্যে অপারেশনগুলি লেজি (Lazy) হয়, যা শুধু তখনই কার্যকরী হয় যখন এগুলিকে কোনো অপারেশন বা ফাংশন প্রয়োগ করা হয়।
২. লেজি কালেকশনস (Lazy Collections)
লেজি কালেকশনস এমন কালেকশন যা কোনো অপারেশন সম্পাদন করার সময় তাদের উপাদানগুলোকে একসাথে লোড না করে, বরং প্রয়োজনে পরবর্তী উপাদানগুলি প্রক্রিয়া করে। অর্থাৎ, লেজি কালেকশনগুলো কেবল তখনই উপাদান তৈরি বা প্রক্রিয়া করে যখন তা প্রয়োজন হয়।
স্কালাতে লেজি কালেকশনস সাধারণত Stream হিসেবে পরিচিত এবং এটি lazy val অথবা Stream ডেটা টাইপের মাধ্যমে তৈরি করা হয়।
স্ট্রিম এবং লেজি কালেকশনস এর উদাহরণ:
উদাহরণ ১: স্ট্রিম ব্যবহার
স্কালাতে Stream ডেটা টাইপটি লেজি অপারেশন করে। এখানে, স্ট্রিমের উপর যে কোনো অপারেশন প্রযোজ্য হলে, কেবলমাত্র প্রয়োজনীয় উপাদানগুলিই তৈরি করা হয়।
// Lazy evaluation using Stream
val numbers: Stream[Int] = Stream.from(1) // Infinite Stream starting from 1
val firstTenNumbers = numbers.take(10).toList // Only takes the first 10 numbers
println(firstTenNumbers) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)এখানে, Stream.from(1) একটি ইনফিনিট স্ট্রিম তৈরি করছে যা ১ থেকে শুরু হয়, এবং take(10) ব্যবহার করে প্রথম ১০টি উপাদান নেওয়া হচ্ছে। গুরুত্বপূর্ণ ব্যাপার হলো, স্ট্রিমে উপাদানগুলো লেজি (lazy)ভাবে তৈরি হয়, তাই কেবলমাত্র যখন take(10) প্রয়োগ করা হয়, তখনই পরবর্তী ১০টি উপাদান প্রক্রিয়া হয়।
উদাহরণ ২: স্ট্রিমের সাথে লেজি অপারেশন
স্ট্রিমের সাথে লেজি অপারেশন যেমন map, filter ইত্যাদি ব্যবহার করলে প্রক্রিয়া করা হয় না যতক্ষণ না তা দরকার হয়।
val numbers: Stream[Int] = Stream.from(1)
// Applying a lazy operation
val lazySquares = numbers.map(x => x * x).take(5).toList
println(lazySquares) // List(1, 4, 9, 16, 25)এখানে, map অপারেশন দিয়ে প্রতিটি সংখ্যাকে স্কোয়ার করা হয়েছে, তবে উপাদানগুলো প্রক্রিয়া করা হচ্ছে লেজি (lazy)ভাবে যখন take(5) প্রয়োগ করা হয় এবং কেবলমাত্র প্রথম ৫টি উপাদান স্কোয়ার করা হয়।
উদাহরণ ৩: লেজি কালেকশনস (Lazy Collections) - Stream এর সুবিধা
স্ট্রিম ব্যবহারের আরেকটি উদাহরণ যেখানে বড় ডেটা সেটের মধ্যে খোঁজা হয়, কিন্তু স্ট্রিমের মাধ্যমে শুধুমাত্র প্রয়োজনীয় উপাদানটি পাওয়া যায়।
val largeRange = Stream.range(1, 1000000) // Lazy sequence of numbers from 1 to 999999
// Filtering to find the first number greater than 500
val firstMatch = largeRange.filter(_ > 500).head
println(firstMatch) // 501এখানে, আমরা Stream.range(1, 1000000) দিয়ে একটি বড় রেঞ্জ তৈরি করেছি, কিন্তু স্ট্রিমটি লেজি এবং সুতরাং শুধুমাত্র যখন filter(_ > 500) প্রয়োগ করা হয় তখনই সেই উপাদানগুলো প্রক্রিয়া করা হয়। অতএব, প্রথম মিল পাওয়া উপাদানটি (যেমন ৫০১) ফিরে আসবে, এবং স্ক্যান করা হবে না পুরো রেঞ্জ।
উদাহরণ ৪: ইনফিনিট রেঞ্জ এবং লেজি অপারেশন
একটি ইনফিনিট রেঞ্জ তৈরি করা এবং তার উপর লেজি অপারেশন প্রয়োগ করার একটি উদাহরণ:
val infiniteRange: Stream[Int] = Stream.from(1)
// Take the first 10 odd numbers from an infinite range
val firstTenOddNumbers = infiniteRange.filter(_ % 2 != 0).take(10).toList
println(firstTenOddNumbers) // List(1, 3, 5, 7, 9, 11, 13, 15, 17, 19)এখানে, Stream.from(1) দিয়ে একটি ইনফিনিট স্ট্রিম তৈরি করা হয়েছে, এবং তার উপরে filter ও take(10) অপারেশন ব্যবহার করা হয়েছে শুধুমাত্র প্রথম ১০টি বিজোড় সংখ্যা পাওয়ার জন্য। কারণ স্ট্রিম লেজি, তাই শুধুমাত্র যখন take(10) প্রয়োগ করা হয় তখনই এটির উপাদান প্রক্রিয়া করা হয়।
সারাংশ:
- স্ট্রিম এবং লেজি কালেকশনস ব্যবহারে ডেটা প্রক্রিয়া করার সময় লেজি (lazy) evaluation ব্যবহার করা হয়, যেখানে উপাদানগুলো একসাথে লোড বা প্রক্রিয়া না করে প্রয়োজনের সময় তৈরি এবং প্রক্রিয়া করা হয়।
- এটি মেমরি এবং পারফরম্যান্সের দিক থেকে উপকারী হতে পারে, কারণ বড় ডেটা সেট বা অন্তহীন ডেটা ডাইনামিকভাবে হ্যান্ডেল করা যায়।
Streamব্যবহার করে স্ট্রিম থেকে শুধু প্রয়োজনীয় উপাদানগুলি তোলা যায়, এবং বিভিন্ন লেজি অপারেশন যেমনmap,filter,take,dropইত্যাদি এর সাথে ব্যবহার করা যায়।
এই ফিচারটি বিশেষভাবে তখন কার্যকরী, যখন বড় ডেটা সেটের সাথে কাজ করা হয় অথবা আপনি যদি সীমিত বা নির্দিষ্ট সংখ্যক উপাদান প্রক্রিয়া করতে চান।
Read more