المسارات
/
Julia
Julia
/
التمارين
/
محنة الترتيب
محنة الترتيب

محنة الترتيب

تمرين تعلّمي

مقدمة

توفّر Julia، مثل معظم لغات البرمجة، تنوّعًا غنيًّا من أنواع المجموعات.

بعضها مرتّب بطبيعته (بما في ذلك Vectors وArrays متعددة الأبعاد)، لذا يمكننا الوصول إلى العناصر حسب موضعها. ومجموعات أخرى غير مرتّبة (Sets، Dicts)، ويجب الوصول إلى عناصرها حسب المفتاح أو القيمة.

في أبسط الحالات، لنفترض أن لدينا Vector من Ints، ونريد ترتيبها ترتيبًا تصاعديًا.

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

julia> sort(v)
4-element Vector{Int64}:
 1
 2
 3
 4

# sort descending
julia> sort(v, rev=true)
4-element Vector{Int64}:
 4
 3
 2
 1

الأمر بسيط! اسم الدالة sort() واضح، ويبدو أنها تُرجع Vector مرتّبًا.

أمزح فقط! في هذه المرحلة من المنهج، ربما تشك (وأنت محق) في وجود تفاصيل دقيقة نحتاج إلى مناقشتها.

الدوال المعدِّلة مقابل الدوال غير المعدِّلة

بعد تشغيل sort(v)، ما قيمة v؟

julia> v
4-element Vector{Int64}:
 3
 2
 4
 1

julia> issorted(v)
false

لم يتغيّر المتجه الأصلي. الدالة sort() هي دالة غير معدِّلة تُرجع نسخة من مدخلها.

هذا تصميم جيد في سياقات كثيرة: لدينا دالة نقية يسهل استنتاج سلوكها، حتى في الكود المتوازي والموزّع.

من ناحية أخرى، لنفترض أن لدينا مصفوفة من مليار سلسلة نصية، وأردنا ترتيبها.

ترتيبها سيكون بطيئًا على الأرجح. إضافة إلى ذلك، نحتاج إلى نسخ كل شيء (بطيء! )، وحجز ذاكرة كافية (عدة غيغابايتات!) لتخزين النسخة.

قارن هذا الكود المشابه إلى حد كبير:

# v is as previously

julia> issorted(v)
false

julia> sort!(v)
4-element Vector{Int64}:
 1
 2
 3
 4

julia> v
4-element Vector{Int64}:
 1
 2
 3
 4

julia> issorted(v)
true

الآن أصبح Vector المُدخل مرتّبًا في مكانه، دون نسخ، وفُقد الترتيب الأصلي نهائيًا.

قد يكون هذا فعّالًا، وقد يكون مليئًا بالأخطاء ويؤدي إلى آثار جانبية غير متوقعة، وقد يربك الآخرين الذين يستخدمون كودك. اختر بحذر!

الدالة sort!() هي «دالة معدِّلة»، وبحسب عُرف (قوي جدًا)، تُضاف علامة ! إلى اسم أي دالة تعدّل مدخلاتها، كتنبيه للمبرمجين.

مصفوفة فهارس الترتيب

إذا كانت العناصر التي نرتّبها كائنات كبيرة، فقد يكون التعامل مع فهرس موضعها أسهل.

julia> langs = ["Julia", "C++", "Python", "Elixir"]
4-element Vector{String}:
 "Julia"
 "C++"
 "Python"
 "Elixir"

julia> inxs = sortperm(langs)  # => Integers
4-element Vector{Int64}:
 2
 4
 1
 3

julia> langs[inxs]  # sort the entire vector
4-element Vector{String}:
 "C++"
 "Elixir"
 "Julia"
 "Python"

julia> langs[inxs[1:2]]  # slice the indices
2-element Vector{String}:
 "C++"
 "Elixir"

لأن langs متجه، فإن كل فهرس هو عدد صحيح في النطاق 1:length(langs). وما تُرجعه sortperm() هو تبديل لهذه الأعداد الصحيحة، ويقابل ترتيبًا لمتجه الإدخال.

التعليمات

لقد تم تعيينك مهندس إنتاج مساعد في شركة تنتج لُحفًا للسلاحف.

تصل الطلبات على مدار اليوم على هيئة اسم عميل أو رقمه وكمية الطلب. ثم تُعالَج هذه الطلبات في الصباح قبل أن يبدأ إنتاج اليوم.

يُسمح لك بالعودة إلى المنزل بأجر كامل بمجرد تنفيذ جميع طلبات اليوم، لذا لديك حافز لتقصير يوم العمل قدر الإمكان. وبما أن كل طلب يُنفَّذ على آلة واحدة، فإن جدولة أكبر الطلبات أولًا تسمح بإلقاء عبء بدء المهمة على الطلبات الأصغر، ما يقلّل إجمالي زمن الإنتاج. لذلك قرّرت توفير بعض دوال الترتيب للمساعدة في تسريع هذه الجدولة، حتى تعود إلى المنزل وتحيك كنزة لسلحفاتك.

1. رتّب الكميات!

كما ذُكر، ستحتاج مصفوفة الكميات إلى الترتيب من الأكبر إلى الأصغر. نظرًا لأن هذه المصفوفات قد تكون كبيرة الحجم، فينبغي ترتيبها في مكانها. ولتتبّع كل شيء بشكل صحيح، ستحتاج أيضًا إلى القدرة على ترتيب مصفوفة العملاء بما يطابق الكميات، لذا ستحتاج إلى تبديلة ترتيب للكميات.

اكتب دالة sortquantity!(qty) تأخذ Vector من الكميات من النوع Integer. ترتّب هذه الدالة المدخل qty في مكانه بترتيب تنازلي وتُرجع تبديلة ترتيب لهذا الترتيب.

julia> qty = [8, 9, 5, 6]
4-element Vector{Int64}:
 8
 9
 5
 6

julia> sortquantity!(qty)
4-element Vector{Int64}:
 2
 1
 4
 3

julia> qty # original vector is sorted in-place
4-element Vector{Int64}:
 9
 8
 6
 5

2. رتّب العميل

كما ذُكر أعلاه، تحتاج إلى تتبّع العملاء بترتيب محدّد.

اكتب دالة sortcustomer(cust, srtperm) تأخذ Vector من العملاء cust و Vector يمثّل تبديلة ترتيب srtperm. تُرجع هذه الدالة مصفوفة جديدة بالعملاء بالترتيب الذي تحدّده تبديلة الترتيب.

julia> cust = ["a", "b", "c"]
3-element Vector{String}:
 "a"
 "b"
 "c"

julia> sortcustomer(cust, [2, 3, 1])
3-element Vector{String}:
 "b"
 "c"
 "a"

julia> cust # original vector remains unsorted
3-element Vector{String}:
 "a"
 "b"
 "c"

3. جدول الإنتاج!

الآن يمكنك جمع كل ذلك معًا للمساعدة في إبقاء تلك السلاحف دافئة! يمكنك الآن ترتيب الكميات والعملاء بشكل صحيح، لكنك تحتاج إلى القدرة على استعادة الترتيب الأصلي للشحن. ويمكن فعل ذلك باستخدام تبديلة ترتيب عكسية.

اكتب دالة production_schedule!(cust, qty) تأخذ Vector من العملاء و Vector من الكميات. ترتّب هذه الدالة الكميات في مكانها بترتيب تنازلي. وتُرجع Vector جديدًا من العملاء مرتّبين بالترتيب نفسه الذي عليه الكميات، بالإضافة إلى تبديلة ترتيب عكسية يمكن استخدامها لإعادة المتجهات المرتّبة إلى ترتيبها الأصلي.

julia> cust, qty = ["a", "b", "c"], [2, 3, 1]
(["a", "b", "c"], [2, 3, 1])

julia> orderedcust, invperm = production_schedule!(cust, qty)
(["b", "a", "c"], [2, 1, 3])

julia> qty # has been sorted in-place
3-element Vector{Int64}:
 3
 2
 1

julia> orderedcust[invperm], qty[invperm] # inverse permutation gives original ordering
(["a", "b", "c"], [2, 3, 1])
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Julia Exercism

مستعد لبدء محنة الترتيب؟

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