التابع Enumerable.sort_by
في روبي
يرتِّب التابع sort_by
عناصر الكائن القابل للتعداد الذي استدعي معه باستعمال مجموعة من المفاتيح المولدة عبر تمرير قيم العناصر إلى الكتلة المعطاة.
لا يُضمَن بأن تكون النتيجة مستقرة. عندما تعيد عملية الموازنة بين مفتاحين القيمة 0، إذ لن يُتوقَع كيفية ترتيب هذين العنصرين ومن منهما سيسبق الآخر.
إن لم تُعطَ أية كتلة، فسيعيد التابع كائنًا جديدًا من النوع Enumerator
.
البنية العامة
sort_by { |obj| block } → array
sort_by → an_enumerator
التنفيذ الحالي للتابع sort_by
يولد مصفوفةً من الصفوف (tuples) تحوي مجموعة العناصر الأصلية والقيم المعيَّنة إلى كلٍّ منها. هذا يجعل تنفيذ التابع sort_by
يستهلك كثيرًا من الموارد عندما تكون مجموعات المفاتيح بسيطة.
require 'benchmark'
a = (1..100000).map { rand(100000) }
Benchmark.bm(10) do |b|
b.report("Sort") { a.sort }
b.report("Sort by") { a.sort_by { |a| a } }
end
ناتج تنفيذ الشيفرة هو:
user system total real
Sort 0.180000 0.000000 0.180000 ( 0.175469)
Sort by 1.980000 0.040000 2.020000 ( 2.013586)
على أي حال، افترض أن موازنة المفاتيح هي عملية مهمة. ترتِّب الشيفرة التالية بعض الملفات بحسب وقت التعديل باستعمال التابع sort
الأساسي:
files = Dir["*"]
sorted = files.sort { |a, b| File.new(a).mtime <=> File.new(b).mtime }
sorted #=> ["mon", "tues", "wed", "thurs"]
للأسف، عملية الترتيب هذه غير ناجعة، إذ تولد كائنين جديدين من النوع File
أثناء إجراء كل عملة موازنة. هنالك تقنية أفضل بعض الشيء وهي استعمال التابع Kernel.test
لتوليد أوقات التعديل مباشرة:
files = Dir["*"]
sorted = files.sort { |a, b|
test(?M, a) <=> test(?M, b)
}
sorted #=> ["mon", "tues", "wed", "thurs"]
هذا لا يزال يولد العديد من الكائنات Time
غير الضرورية. هنالك طريقة أفضل وهي تخزين مفاتيح الترتيب (التي هي أوقات التعديل في حالتنا هذه) قبل إجراء عملية الترتيب. يسمي مستخدمو Perl غالبًا هذه الطريقة "تحويل شورتزيان" (Schwartzian transform) نسبةً إلى راندال شوارتز (Randal Schwartz). سننشئ أولًا مصفوفة مؤقتة، إذ يكون كل عنصر مصفوفةً - بحد ذاته - تحوي مفاتيح الترتيب جنبًا إلى جنب مع اسم الملف. سنرتب هذه المصفوفة ثم نستخرج اسم الملف منها بعدئذٍ:
sorted = Dir["*"].collect { |f|
[test(?M, f), f]
}.sort.collect { |f| f[1] }
sorted #=> ["mon", "tues", "wed", "thurs"]
هذا بالضبط ما يفعله التابع sort_by
ضمنيًّا:
sorted = Dir["*"].sort_by { |f| test(?M, f) }
sorted #=> ["mon", "tues", "wed", "thurs"]
القيمة المعادة
تعاد مصفوفة جديد تحوي عناصر الكائن القابل للترتيب المعطى بعد ترتيبها.
أمثلة
مثال على استعمال التابع sort_by
:
%w{apple pear fig}.sort_by { |word| word.length }
#=> ["fig", "pear", "apple"]
انظر أيضًا
- التابع
map
: يعيد مصفوفة جديدة تحوي النتائج المقابلة لكل عنصر من عناصر الكائن القابل للتعداد المعادة من الكتلة المعطاة بعد تمريره إليها.
- التابع
sort
: يرتِّب عناصر الكائن القابل للترتيب الذي استدعي معه ثم يعيدها في مصفوفة.