در مفهوم Vectors گفتیم که «آرایه قلب زبان Julia است» و بردار یکبعدی است.
با این حساب، میتوان بهدرستی امید داشت که زبان روشهای گوناگون و قدرتمندی برای انجام کارها با بردارها فراهم کند، هر معنایی که داشته باشد.
برخی توابع بسیار ساده یک ورودی بردار میگیرند و یک خروجی اسکالر برمیگردانند.
v = [2, 3, 4]
length(v) # => 3
sum(v) # => 9
فرض کنید یک بردار عددی دارید و میخواهید از هر مقدار ۰٫۵ کم کنید.
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 است.
انتخاب عناصر یک بردار بر اساس شمارهی نمایه در مفاهیم قبلی بحث شده است.
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]