بر

بردار در Julia

1 تمرین

درباره‌ی بردار

یکی از هدف‌های اصلی Julia این است که بتواند محاسبات را روی داده‌های عددی، سریع و کارآمد انجام دهد. حجم انبوهی از داده‌های عددی.

معمولاً این داده‌ها در آرایه‌ها (یا نوعی مرتبط با آن‌ها) ذخیره می‌شوند؛ بنابراین می‌توان گفت که آرایه‌ها قلب زبان Julia هستند.

آرایه‌ها می‌توانند اندازه‌ی دلخواه داشته باشند (تنها محدود به حافظه‌ی سخت‌افزار شما) و می‌توانند هر تعداد بُعد داشته باشند.

برخی از انواع آرایه اسم‌های ویژه‌ای دارند (که از جبر خطی گرفته شده‌اند). آرایه‌ی یک‌بُعدی Vector و آرایه‌ی دوبُعدی Matrix نامیده می‌شود. هر دو در Julia زیرنوع‌هایی از Array هستند.

این مفهوم مقدماتی بر پایه‌های بردارها تمرکز دارد. آرایه‌های چندبُعدی بعداً در برنامه‌ی درسی پوشش داده می‌شوند.

ساختن بردار

در Julia، یک بردار دنباله‌ای مرتب از مقادیر است که می‌توان با شماره‌ی ایندکس به آن‌ها دسترسی پیدا کرد.

ساده‌ترین راه برای ساختن یک بردار این است که مقادیر را داخل کروشه فهرست کنید:

julia> num_vec = [1, 4, 9]
3-element Vector{Int64}:
 1
 4
 9

julia> str_vec = ["arrays", "are", "important"]
3-element Vector{String}:
 "arrays"
 "are"
 "important"

نوع بردار با نوع هر عنصر مطابقت دارد.

از نظر فنی، این یک بردار ستونی است، اما اگر با جبر خطی آشنایی ندارید فعلاً آن را نادیده بگیرید. پس از مفهوم آرایه‌های چندبُعدی، این موضوع بیشتر روشن می‌شود.

یعنی بردارها باید همگن باشند (همه‌ی عناصر از یک نوع)؟

تا حدی بله، و اگر بهترین کارایی را می‌خواهید، توصیه می‌شود همین را هدف بگیرید. با این حال، Julia در صورت نیاز می‌تواند با استفاده از نوع Any این محدودیت را دور بزند:

julia> mixed_vector = [1, "str", 'c']
3-element Vector{Any}:
 1
  "str"
  'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)

هنگام ساختن یک بردار خالی، Julia به‌طور پیش‌فرض نوع عنصر را Any در نظر می‌گیرد، اما می‌توان با مشخص کردن نوع عنصر دلخواه روی آرایه‌ی خالی، آن را دقیق‌تر تعریف کرد.

julia> empty_vec = []
Any[]

julia> empty_int_vec = Int64[]
Int64[]

بردارهای از پیش پرشده

بسیار رایج است که کار را با بردارهایی از مقادیر همه‌صفر یا همه‌یک شروع کنید. برای این کار، توابعی به اسم (که جای تعجب ندارد) zeros() و ones() وجود دارند که اندازه‌ی بردار را به عنوان پارامتر می‌گیرند. نوع پیش‌فرض Float64 است، اما در صورت تمایل می‌توان انواع عددی دیگر را هم مشخص کرد.

به همین ترتیب، تابع fill() هم مقداری برای تکرار و هم اندازه‌ی دلخواه بردار را می‌گیرد.

julia> zeros(3)
3-element Vector{Float64}:
 0.0
 0.0
 0.0

julia> ones(3)
3-element Vector{Float64}:
 1.0
 1.0
 1.0

julia> ones(Int64, 3)
3-element Vector{Int64}:
 1
 1
 1

julia> fill(42, 3)
3-element Vector{Int64}:
 42
 42
 42

گزینه‌های بسیار دیگری هم وجود دارد: به راهنما مراجعه کنید.

لطفاً این قانون را بخوانید و به خاطر بسپارید:

  • به‌طور پیش‌فرض، ایندکس‌گذاری در Julia از ۱ شروع می‌شود، نه ۰.

این موضوع برای هر کسی که با زبان‌های دیگر علم داده (R، Matlab، Fortran و...) کار کرده باشد آشناست، اما ممکن است برای دانشمندان کامپیوتر با پیشینه‌ی زبان‌های شبیه C تکان‌دهنده به نظر برسد.

در بقیه‌ی موارد، ایندکس‌ها همان‌طور که حدس می‌زنید کار می‌کنند: کافی است آن‌ها را داخل کروشه بگذارید:

squares = [0, 1, 4, 9, 16]
squares[1]  # 0
squares[3]  # 4
squares[begin]  # 0 ("begin" is synonym for 1)
squares[end]  # 16 ("end" is synonym for length(squares))

به مزیت ایندکس‌گذاری با end (که بسیار کاربردی است) و begin (که احتمالاً نه) توجه کنید.

شاید برنامه‌نویسان Python کنجکاو باشند که ایندکس‌های منفی چه می‌شوند. نگران نباشید: این‌ها بخشی از Julia نیستند و باعث BoundsError می‌شوند، همان‌طور که هر ایندکسی کوچک‌تر از ۱ یا بزرگ‌تر از length(squares) چنین خواهد کرد.

عملیات بردار

بردارها در Julia تغییرپذیر هستند: می‌توانیم محتوای خانه‌های تک‌تک را تغییر دهیم.

julia> vals = [1, 3, 5, 7]
4-element Vector{Int64}:
 1
 3
 5
 7

julia> vals[2] = 4  # reassign the value of this element
4

# Only the value at position 2 changes:
julia> vals
4-element Vector{Int64}:
 1
 4
 5
 7

توابع بسیاری برای دستکاری بردارها در دسترس است، هرچند مستندات Julia آن‌ها را به‌جای بردارها به شکل کلی به «مجموعه‌ها» تعمیم می‌دهد.

توجه داشته باشید که طبق قرارداد، توابعی که ورودی خود را تغییر می‌دهند، ! در اسمشان دارند. کامپایلر این را اجبار نمی‌کند، اما در دنیای Julia قراردادی بسیار قوی است.

این‌ها چند مورد از توابع کاربردی هستند:

  • برای افزودن مقادیر به انتهای بردار، از push!() استفاده کنید.
  • برای حذف آخرین مقدار، از pop!() استفاده کنید.
  • برای کار روی ابتدای بردار، توابع متناظر pushfirst!() و popfirst!() هستند.
  • برای درج یا حذف یک عنصر در هر موقعیتی، insert!() و deleteat!() وجود دارند.
julia> vals = [1, 3]
2-element Vector{Int64}:
 1
 3

julia> push!(vals, 5, 6)  # can add multiple values
4-element Vector{Int64}:
 1
 3
 5
 6

julia> pop!(vals)  # mutates vals, return popped value
6

julia> vals
3-element Vector{Int64}:
 1
 3
 5

الحاق

الحاق برای بردارها نسبتاً ساده است، هرچند نگاهی به راهنما هشدار می‌دهد که هنگام در نظر گرفتن آرایه‌های چندبُعدی، پیچیدگی‌هایی در انتظار است.

تابع append!() می‌تواند ترکیبی از چند بردار و عناصر تکی را به عنوان ورودی بگیرد.

julia> append!([1, 2], [3, 4], [-1, -2], 15)
7-element Vector{Int64}:
  1
  2
  3
  4
 -1
 -2
 15
ویرایش از طریق GitHub این پیوند در پنجره یا زبانه‌ی جدیدی باز می‌شود

بردار را یاد بگیرید