فرز المصفوفات في Swift: اختبارات أداء مذهلة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

أداء Swift Beta: فرز المصفوفات — ما الخطأ الذي حدث؟

\n\n

إذا كنت قد ألقيت نظرة على Stack Overflow في عصر الإصدارات التجريبية الأولى من Swift، فبالتأكيد تتذكر السؤال الأسطوري الذي جمع آلاف المشاهدات ومئات التعليقات. كان نصه تقريبًا: «لماذا يعمل فرز المصفوفات في Swift Beta أبطأ بمقدار 100 مرة من Objective-C؟»

\n\n

في ذلك الوقت، في عام 2014، كانت هذه صدمة حقيقية لمجتمع iOS. المطورون الذين اعتادوا على الفرز السريع للغاية في Objective-C، رأوا فجأة تطبيقاتهم تتجمد دون سبب واضح. اليوم، بعد سنوات، يمكننا تحليل هذه المشكلة بهدوء: فهم ما الذي تسبب في البطء بالضبط، وكيف تطور Swift، والأهم من ذلك، كيفية فرز المصفوفات بشكل صحيح في Swift الحديث لتجنب تكرار أخطاء الماضي.

\n\n

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

\n\n

خلفية مختصرة: ماذا حدث في Swift Beta؟

\n\n

في الإصدار التجريبي الأول من Swift، كان فرز مصفوفة من 100,000 عدد صحيح قد يستغرق ما يصل إلى 20 ثانية. في Objective-C، كانت نفس العملية تتم في 0.2 ثانية. الفرق 100 مرة! كان السبب هو أن Swift المبكر استخدم تنفيذًا غير فعال لخوارزمية الفرز (Introsort مع اختيار سيئ للعنصر المحوري)، بالإضافة إلى مشاكل في التحسين عند الترجمة بدون أعلام التحسين (-O).

\n\n

علاوة على ذلك، في الإصدار التجريبي، غالبًا ما كان يتم تفعيل آلية التحقق الديناميكي من الحدود (bounds checking) لكل وصول إلى المصفوفة، مما أضاف تكاليف إضافية هائلة. كان الاستنتاج بسيطًا: Swift كان غير ناضج، لكن إمكاناته كانت هائلة.

\n\n

كيفية فرز المصفوفات في Swift اليوم؟ أفضل الممارسات

\n\n

Swift الحديث (الإصدار 5.x وما بعده) هو لغة ناضجة. أصبح فرز المصفوفات ليس سريعًا فحسب، بل واحدًا من أسرع الطرق بين اللغات الرئيسية. دعنا نحلل الطرق الأساسية.

\n\n

1. الطريقة المدمجة sort() — المعيار الذهبي

\n\n

أبسط وأفضل طريقة موصى بها هي استخدام طريقة sort() (الفرز في المكان) أو sorted() (إرجاع مصفوفة مرتبة جديدة).

\n\n
import Foundation\n\nvar numbers = [5, 3, 8, 1, 9, 2]\nnumbers.sort() // فرز في المكان\nprint(numbers) // [1, 2, 3, 5, 8, 9]\n\nlet sortedNumbers = numbers.sorted() // إرجاع مصفوفة جديدة\nprint(sortedNumbers) // [1, 2, 3, 5, 8, 9]
\n\n

داخليًا، تستخدم sort() TimSort — خوارزمية هجينة تعمل بتعقيد O(n log n) في المتوسط و O(n) على البيانات شبه المرتبة. هذه هي نفس الخوارزمية المستخدمة في Python و Java. وهي محسّنة بشكل رائع للمعالجات الحديثة.

\n\n

2. الفرز باستخدام الإغلاق: التخصيص

\n\n

إذا كنت بحاجة إلى فرز مصفوفة تنازليًا أو وفقًا لمعيار معقد، استخدم الإغلاق:

\n\n
let words = ["تفاحة", "برتقال", "موز", "كيوي"]\nlet sortedByLength = words.sorted { $0.count < $1.count }\nprint(sortedByLength) // ["كيوي", "تفاحة", "موز", "برتقال"]\n\nlet descendingNumbers = numbers.sorted(by: >)\nprint(descendingNumbers) // [9, 8, 5, 3, 2, 1]
\n\n

هام: يجب أن يكون الإغلاق دالة نقية (pure function) — بدون آثار جانبية. وإلا فإنك تخاطر بسلوك غير متوقع وانخفاض في الأداء.

\n\n

3. فرز الهياكل المخصصة

\n\n

عند العمل مع أنواع البيانات الخاصة بك، من الأفضل تنفيذ بروتوكول Comparable. سيسمح ذلك باستخدام sort() بدون إغلاق.

\n\n
struct Person: Comparable {\n    let name: String\n    let age: Int\n\n    static func < (lhs: Person, rhs: Person) -> Bool {\n        return lhs.age < rhs.age // الفرز حسب العمر\n    }\n}\n\nle                

المدونات

توصيات الكتب