توفّر 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() هو تبديل لهذه الأعداد الصحيحة، ويقابل ترتيبًا لمتجه الإدخال.
لقد تم تعيينك مهندس إنتاج مساعد في شركة تنتج لُحفًا للسلاحف.
تصل الطلبات على مدار اليوم على هيئة اسم عميل أو رقمه وكمية الطلب. ثم تُعالَج هذه الطلبات في الصباح قبل أن يبدأ إنتاج اليوم.
يُسمح لك بالعودة إلى المنزل بأجر كامل بمجرد تنفيذ جميع طلبات اليوم، لذا لديك حافز لتقصير يوم العمل قدر الإمكان. وبما أن كل طلب يُنفَّذ على آلة واحدة، فإن جدولة أكبر الطلبات أولًا تسمح بإلقاء عبء بدء المهمة على الطلبات الأصغر، ما يقلّل إجمالي زمن الإنتاج. لذلك قرّرت توفير بعض دوال الترتيب للمساعدة في تسريع هذه الجدولة، حتى تعود إلى المنزل وتحيك كنزة لسلحفاتك.
كما ذُكر، ستحتاج مصفوفة الكميات إلى الترتيب من الأكبر إلى الأصغر. نظرًا لأن هذه المصفوفات قد تكون كبيرة الحجم، فينبغي ترتيبها في مكانها. ولتتبّع كل شيء بشكل صحيح، ستحتاج أيضًا إلى القدرة على ترتيب مصفوفة العملاء بما يطابق الكميات، لذا ستحتاج إلى تبديلة ترتيب للكميات.
اكتب دالة 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
كما ذُكر أعلاه، تحتاج إلى تتبّع العملاء بترتيب محدّد.
اكتب دالة 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"
الآن يمكنك جمع كل ذلك معًا للمساعدة في إبقاء تلك السلاحف دافئة! يمكنك الآن ترتيب الكميات والعملاء بشكل صحيح، لكنك تحتاج إلى القدرة على استعادة الترتيب الأصلي للشحن. ويمكن فعل ذلك باستخدام تبديلة ترتيب عكسية.
اكتب دالة 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])
سجّل في Exercism لتتعلّم وتتقن Julia عبر 35 مفهومًا128 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.