المسارات
/
Julia
Julia
/
التمارين
/
مراقب الطيور
مراقب الطيور

مراقب الطيور

تمرين تعلّمي

مقدمة

في مفهوم Vectors، قلنا إن "المصفوفات هي قلب لغة 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، ونحتاج إلى فهم ما تفعله النقطة.

أمران يتحدان ليعطيا النتيجة المرجوة.

1. التطبيق عنصرًا عنصرًا

أولًا، إضافة نقطة قبل أي عامل بيني تعني "طبّق هذه العملية على كل عنصر على حدة".

وبالمثل، إضافة نقطة بعد اسم دالة يجعلها تعمل على المتجهات كلها، حتى لو كانت الدالة مكتوبة أصلًا لمدخلات قياسية.

julia> sqrt.([1, 4, 9])
3-element Vector{Float64}:
 1.0
 2.0
 3.0

2. توسيع القيم المفردة

رأينا في مثال سابق أنه يمكننا طرح متجهات متساوية الطول، لكن اعلم من فضلك أن .- عامل أكثر أمانًا من - لأنه يوضّح نية العمل عنصرًا عنصرًا.

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

بشكل عام، الأطوال غير المتساوية خطأ، إلا إذا كان طول أحدهما 1 (وهو ما يُسمى تقنيًا بُعدًا "مفردًا").

القيم المفردة مثل [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

التعليمات

أنت مراقب طيور شغوف يتابع عدد الطيور التي زارت حديقتك خلال الأيام السبعة الماضية.

لديك ست مهام، وكلها تتعلق بأعداد الطيور التي زارت حديقتك.

1. تحقق من عدد الطيور التي زارت اليوم

نفّذ الدالة today() لتُرجع عدد الطيور التي زارت حديقتك اليوم. أعداد الطيور مرتّبة حسب اليوم، بحيث يمثّل العنصر الأول عدد أقدم يوم، ويمثّل العنصر الأخير عدد اليوم.

julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> today(birds_per_day)
1

2. زد عدد اليوم

نفّذ الدالة 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]

3. تحقق مما إذا كان هناك يوم دون طيور زائرة

نفّذ الدالة 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

4. احسب عدد الطيور الزائرة خلال أول عدد من الأيام

نفّذ الدالة count_for_first_days() التي تُرجع عدد الطيور التي زارت حديقتك من بداية الأسبوع، لكن اقتصر العدد على عدد الأيام المحدد من بداية الأسبوع.

julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> count_for_first_days(birds_per_day, 4)
14

5. احسب عدد الأيام المزدحمة

بعض الأيام أكثر ازدحامًا من غيرها. اليوم المزدحم هو اليوم الذي زارت فيه خمسة طيور أو أكثر حديقتك. نفّذ الدالة busy_days() لتُرجع عدد الأيام المزدحمة:

julia> birds_per_day = [2, 5, 0, 7, 4, 1]
julia> busy_days(birds_per_day)
2

6. احسب المتوسطات حسب أيام الأسبوع

قررت توسيع سجلاتك بالاحتفاظ بأعداد لعدة أسابيع. في كل حالة، تُرتَّب الأعداد حسب أيام الأسبوع، من الاثنين كأول عنصر إلى الأحد كآخر عنصر.

نفّذ الدالة 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]
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Julia Exercism

مستعد لبدء مراقب الطيور؟

سجّل في Exercism لتتعلّم وتتقن Julia عبر 35 مفهومًا128 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.