كيفية دمج المصفوفات في Swift؟ تحليل كامل مع أمثلة وأسرار الأداء
\n\nإذا كنت قد كتبت أي كود بلغة Swift من قبل، فبالتأكيد واجهت هذه المهمة: "لدي مصفوفتان، كيف أجعلهما مصفوفة واحدة؟". يبدو السؤال بسيطًا، لكنه يخفي عالمًا كاملاً من التحسينات والفروق الدقيقة. على Stack Overflow، حصل هذا السؤال على آلاف المشاهدات - وليس من دون سبب. اليوم لن نعرض فقط كيفية كتابة الكود، بل سننظر تحت غطاء المترجم (compiler) ونعرف ما يحدث حقًا عندما تكتب array1 + array2. هيا بنا!
الطريقة الأكثر وضوحًا: العامل +
\n\nلنبدأ بالكلاسيكيات. في Swift، يمكن جمع المصفوفات مثل الأرقام:
\n\nlet first = [1, 2, 3]\nlet second = [4, 5, 6]\nlet result = first + second\nprint(result) // [1, 2, 3, 4, 5, 6]\n\nجميل؟ نعم. سريع؟ ليس دائمًا. عند استخدام +، يقوم Swift بإنشاء مصفوفة جديدة ونسخ العناصر من كلا المصفوفتين الأصليتين إليها. إذا كانت مصفوفاتك كبيرة (لنقل 100,000 عنصر لكل منها)، فهذا عمل مزدوج للمعالج. لكن انتظر - هناك فارق دقيق يسمى copy-on-write (COW).
سحر Copy-on-Write: كيف يوفر Swift الذاكرة
\n\nSwift لغة ذكية. عندما تقوم ببساطة بتعيين مصفوفة لأخرى، فإنه لا ينسخ البيانات فورًا:
\n\nvar a = [1, 2, 3]\nvar b = a // طالما لم يتم تعديل البيانات، يشير a و b إلى نفس منطقة الذاكرة\nb.append(4) // هنا يحدث النسخ الفعلي: تحصل b على نسختها الخاصة\n\nهذا يسمى copy-on-write. لكن عند الدمج باستخدام +، لا يعمل هذا - النتيجة دائمًا مصفوفة جديدة. لماذا؟ لأننا لا نشير فقط إلى البيانات القديمة، بل ننشئ مجموعة جديدة من عناصر مصدرين مختلفين. لا يمكن للمترجم (compiler) ضمان عدم تغيير المصفوفات الأصلية، لذلك يقوم بنسخ كامل.
طريقة append(contentsOf:): عندما تكون السرعة أهم
\n\nإذا كنت بحاجة إلى إضافة عناصر مصفوفة إلى نهاية مصفوفة أخرى دون إنشاء مصفوفة ثالثة، استخدم append(contentsOf:):
var numbers = [1, 2, 3]\nlet moreNumbers = [4, 5, 6]\nnumbers.append(contentsOf: moreNumbers)\nprint(numbers) // [1, 2, 3, 4, 5, 6]\n\nفي هذه الحالة، لا ينشئ Swift مصفوفة جديدة - بل يوسع المصفوفة الموجودة. إذا كانت المصفوفة numbers تحتوي على ذاكرة محجوزة كافية (capacity)، فسيتم نسخ العناصر الجديدة إلى المساحة الفارغة. إذا لم يكن الأمر كذلك، يحدث إعادة توزيع للذاكرة، لكن هذا لا يزال أسرع من إنشاء مصفوفة من الصفر.
نصيحة محترف: إذا كنت تعلم أنك ستضيف الكثير من العناصر، قم بحجز الذاكرة مسبقًا باستخدام reserveCapacity():
var bigArray: [Int] = []\nbigArray.reserveCapacity(1000)\nfor i in 0..<1000 {\n bigArray.append(i) // لا يوجد نسخ زائد!\n}\n\nطريقة flatMap: دمج المصفوفات مع التحويل
\n\nأحيانًا لا تحتاج فقط إلى ربط المصفوفات، بل أيضًا إلى تحويل كل عنصر. هنا يأتي دور flatMap (أو compactMap للقيم الاختيارية). بالمعنى الدقيق، flatMap مصمم "لتسوية" المجموعات، لكن يمكن استخدامه أيضًا للدمج:
let arrays = [[1, 2], [3, 4], [5, 6]]\nlet flattened = arrays.flatMap { $0 }\nprint(flattened) // [1, 2, 3, 4, 5, 6]\n\nتحت الغطاء، يفعل flatMap نفس الشيء الذي تفعله حلقة مع append(contentsOf:). لكن الكود يصبح أنظف وأكثر قابلية للقراءة. صحيح، إذا كنت تحتاج فقط إلى ربط مصفوفتين - لا تستخدم flatMap، فهو مبالغ فيه.
reduce(into:) للدمج المرن
\n\nإذا كان لديك مصفوفة من المصفوفات وتريد دمجها مع منطق إضافي، جرب reduce(into:):
let arrayOfArrays = [[1, 2], [3, 4], [5, 6]]\nlet merged = arrayOfArrays.reduce(into: [Int]()) { r