Vectors Concept-এ আমরা বলেছিলাম যে, "অ্যারেগুলো Julia ভাষার মূল ভিত্তি", আর একটি ভেক্টর হলো একমাত্রিক।
এটা মাথায় রেখে আমরা যুক্তিসঙ্গতভাবেই আশা করতে পারি যে, ভাষাটি ভেক্টর নিয়ে কিছু করার জন্য বহুমুখী ও শক্তিশালী অনেক উপায় দেবে, সেটা যা-ই হোক না কেন।
কিছু খুব সাধারণ ফাংশন একটি ভেক্টর ইনপুট নেয় এবং একটি স্কেলার আউটপুট রিটার্ন করে।
v = [2, 3, 4]
length(v) # => 3
sum(v) # => 9
ধরুন আপনার কাছে একটি সাংখ্যিক ভেক্টর আছে এবং আপনি প্রতিটি মান থেকে 0.5 বিয়োগ করতে চান।
julia> v = [1.2, 1.5, 1.7]
3-element Vector{Float64}:
1.2
1.5
1.7
julia> v - 0.5
ERROR: MethodError: no method matching -(::Vector{Float64}, ::Float64)
এটা তো ব্যর্থ হলো, তাহলে অন্য একটি ভেক্টর বিয়োগ করলে কী হয়?
julia> v - [0.5, 0.5, 0.5]
3-element Vector{Float64}:
0.7
1.0
1.2
সফল হয় বটে, কিন্তু ভেক্টরগুলো লম্বা হতে থাকলে এটি বেশ ঝামেলার আর প্রচুর মেমোরি খরচ করে।
সৌভাগ্যক্রমে, এই সমস্যাটি খুব সহজেই সমাধান করার জন্য Julia-র কাছে একটি "ম্যাজিক" ডট আছে: আপনার দরকার শুধু v .- 0.5।
পরের অংশে এটির কারণ ব্যাখ্যা করা হয়েছে।
তাহলে দেখুন, v - 0.5 ব্যর্থ হয় কিন্তু v .- 0.5 সফল হয়, আর ডটটি আসলে কী করছে সেটি আমাদের বুঝতে হবে।
দুটি জিনিস, যেগুলো একসাথে মিলে কাঙ্ক্ষিত ফলাফল দেয়।
প্রথমত, যেকোনো ইনফিক্স অপারেটরের আগে একটি ডট বসানোর অর্থ হলো "এই অপারেশনটি প্রতিটি এলিমেন্টে আলাদা আলাদাভাবে প্রয়োগ করা"।
একইভাবে, কোনো ফাংশনের নামের পরে একটি ডট বসালে সেটি "ভেক্টরাইজ" হয়ে যায়, এমনকি ফাংশনটি যদি স্কেলার ইনপুটের জন্য লেখা হয়ে থাকে।
julia> sqrt.([1, 4, 9])
3-element Vector{Float64}:
1.0
2.0
3.0
আগের একটি উদাহরণে দেখেছি যে আমরা সমান দৈর্ঘ্যের ভেক্টর বিয়োগ করতে পারি, তবে দয়া করে বুঝে নিন যে এলিমেন্টভিত্তিক উদ্দেশ্যটি স্পষ্ট করে দেওয়ার কারণে .- অপারেটরটি - অপেক্ষা নিরাপদ।
julia> v .- [0.5, 0.5, 0.5]
3-element Vector{Float64}:
0.7
1.0
1.2
অসমান দৈর্ঘ্যের ভেক্টর হলে কী হবে?
julia> v .- [0.5, 0.5]
ERROR: DimensionMismatch: arrays could not be broadcast to a common size
julia> v .- [0.5,]
3-element Vector{Float64}:
0.7
1.0
1.2
সাধারণভাবে, অসমান দৈর্ঘ্য একটি এরর, তবে তখন নয় যখন একটির দৈর্ঘ্য ১ (প্রযুক্তিগতভাবে একটি "সিঙ্গেলটন" ডাইমেনশন)।
সিঙ্গেলটন, যেমন [0.5,] বা শুধু 0.5, পুনরাবৃত্তির মাধ্যমে স্বয়ংক্রিয়ভাবে প্রয়োজনীয় দৈর্ঘ্যে সম্প্রসারিত হয়।
এই ধারণাটিই broadcasting-এর মূল ভিত্তি।
ইনডেক্স নম্বর দিয়ে একটি ভেক্টরের এলিমেন্ট নির্বাচন নিয়ে আগের Concept-গুলোতে আলোচনা করা হয়েছে।
a = collect('A':'Z') # => 26-element Vector{Char}
# index with an integer
a[2] # => 'B'
# index with a range
a[12:2:18] # => ['L', 'N', 'P, 'R']
# index with another vector
a[ [1, 3, 5] ] # => ['A', 'C', 'E']
কোনো লজিক্যাল এক্সপ্রেশন (প্রযুক্তিগতভাবে একটি "প্রেডিকেট") সন্তুষ্ট করে এমন এলিমেন্টও নির্বাচন করা সম্ভব। এর জন্য সাধারণত ব্রডকাস্টিং লাগে।
julia> a[a .< 'D']
3-element Vector{Char}:
'A': ASCII/Unicode U+0041 (category Lu: Letter, uppercase)
'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)
'C': ASCII/Unicode U+0043 (category Lu: Letter, uppercase)
আরও জটিল এক্সপ্রেশনের ক্ষেত্রে ডটগুলো বেড়ে যেতে থাকে (তবে এগুলো ছোট আর টাইপ করা সহজ)।
julia> a[a .< 'D' .|| a .> 'W']
6-element Vector{Char}:
'A': ASCII/Unicode U+0041 (category Lu: Letter, uppercase)
'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)
'C': ASCII/Unicode U+0043 (category Lu: Letter, uppercase)
'X': ASCII/Unicode U+0058 (category Lu: Letter, uppercase)
'Y': ASCII/Unicode U+0059 (category Lu: Letter, uppercase)
'Z': ASCII/Unicode U+005A (category Lu: Letter, uppercase)
মনে রাখবেন, "ভেক্টর" আসলে যেকোনো উপযুক্ত ক্রমবদ্ধ ইটারেবল হতে পারে, যেমন একটি রেঞ্জ:
julia> n = 3:10
3:10
julia> n[isodd.(n)]
4-element Vector{Int64}:
3
5
7
9
আপনি একজন আগ্রহী পাখি-পর্যবেক্ষক, যিনি গত সাত দিনে আপনার বাগানে কত পাখি এসেছে তার হিসাব রাখেন।
আপনার হাতে ছয়টি কাজ, সবগুলোই আপনার বাগানে আসা পাখির সংখ্যা নিয়ে।
আজ আপনার বাগানে কত পাখি এসেছে তা রিটার্ন করার জন্য today() ফাংশনটি ইমপ্লিমেন্ট করুন।
পাখির সংখ্যাগুলো দিন অনুযায়ী সাজানো, যেখানে প্রথম এলিমেন্টটি সবচেয়ে পুরোনো দিনের সংখ্যা আর শেষ এলিমেন্টটি আজকের সংখ্যা।
julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> today(birds_per_day)
1
আজকের সংখ্যা এক বাড়ানোর জন্য increment_todays_count() ফাংশনটি ইমপ্লিমেন্ট করুন:
julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> increment_todays_count(birds_per_day)
[2, 5, 0, 7, 4, 2]
has_day_without_birds() ফাংশনটি ইমপ্লিমেন্ট করুন, যা true রিটার্ন করে যদি এমন কোনো দিন থাকে যেদিন বাগানে একটিও পাখি আসেনি; অন্যথায় false রিটার্ন করে:
julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> has_day_without_birds(birds_per_day)
true
count_for_first_days() ফাংশনটি ইমপ্লিমেন্ট করুন, যা সপ্তাহের শুরু থেকে আপনার বাগানে আসা পাখির সংখ্যা রিটার্ন করে, তবে হিসাবটি সপ্তাহের শুরু থেকে নির্দিষ্ট সংখ্যক দিনের মধ্যে সীমিত রাখে।
julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> count_for_first_days(birds_per_day, 4)
14
কিছু দিন অন্যদিনের চেয়ে ব্যস্ত থাকে।
ব্যস্ত দিন বলতে সেই দিনকে বোঝায়, যেদিন পাঁচটি বা তার বেশি পাখি আপনার বাগানে এসেছে।
ব্যস্ত দিনের সংখ্যা রিটার্ন করার জন্য busy_days() ফাংশনটি ইমপ্লিমেন্ট করুন:
julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> busy_days(birds_per_day)
2
আপনি একাধিক সপ্তাহের হিসাব রেখে নিজের রেকর্ড বাড়ানোর সিদ্ধান্ত নিলেন। প্রতিটি ক্ষেত্রেই সংখ্যাগুলো সপ্তাহের বার অনুযায়ী সাজানো, প্রথম এন্ট্রি সোমবার আর শেষ এন্ট্রি রবিবার।
দুই সপ্তাহের গড় রিটার্ন করার জন্য average_per_day() ফাংশনটি ইমপ্লিমেন্ট করুন।
julia> week1 = [7, 2, 9, 1, 3, 0, 10]
julia> week2 = [2, 6, 4, 1, 3, 8, 9]
julia> average_per_day(week1, week2)
[4.5, 4.0, 6.5, 1.0, 4.0, 3.0, 9.5]
Exercism-এ সাইন আপ করুন, Julia ট্র্যাকের 35টি কনসেপ্ট128টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।