كيفية حذف عنصر من Slice في Golang: دليل مفصل مع أمثلة
\n\nالعمل مع الشرائح (slices) في Go هو روتين يومي لكل مطور. لكن عملية واحدة تثير تساؤلات حتى لدى مطوري Go ذوي الخبرة: حذف عنصر من الشريحة. قد يبدو الأمر بسيطًا؟ لكن في Go لا توجد دالة مدمجة delete() للشرائح كما هو الحال مع الخرائط (maps). مما يضطرنا لابتكار حلول خاصة.
في هذه المقالة، سنستعرض جميع طرق حذف عنصر من شريحة في Golang: من الحذف البسيط حسب الفهرس إلى الحيل المتقدمة مع الحفاظ على الترتيب وتحسين الذاكرة. ستتعلم كيف تعمل الآلية الداخلية للشرائح، ولماذا لا يعمل التعيين البسيط دائمًا، وكيف تتجنب الأخطاء الشائعة.
\n\nلماذا لا توجد دالة مدمجة لحذف العناصر من الشريحة في Go؟
\n\nقبل الغوص في الكود، دعنا نفهم فلسفة اللغة. الشريحة (slice) في Go هي مجرد "نافذة" على المصفوفة الأساسية. إنها لا تملك البيانات، بل تشير إليها فقط. لذلك، حذف عنصر ليس مسحًا فيزيائيًا للبيانات من الذاكرة (كما في C++)، بل إعادة بناء "النافذة" باستخدام عمليات append والتقطيع (slicing) الذكية.
Go تتيح لك أن تقرر بنفسك كيفية تنظيم الحذف: مع الحفاظ على الترتيب أو بدونه، مع تقليل السعة أو بدونها. هذا يمنحك مرونة، لكنه يتطلب فهمًا جيدًا.
\n\nالطريقة 1: الحذف حسب الفهرس (مع الحفاظ على الترتيب)
\n\nهذه هي الحالة الأكثر شيوعًا. لديك شريحة وتريد إزالة العنصر في الموضع i مع الحفاظ على الترتيب النسبي للعناصر المتبقية.
package main\n\nimport "fmt"\n\nfunc removeIndex(s []int, index int) []int {\n // ندمج الجزء قبل الفهرس مع الجزء بعد الفهرس\n return append(s[:index], s[index+1:]...)\n}\n\nfunc main() {\n slice := []int{1, 2, 3, 4, 5}\n slice = removeIndex(slice, 2) // نحذف العنصر ذا الفهرس 2 (القيمة 3)\n fmt.Println(slice) // [1 2 4 5]\n}\n\n\nكيف يعمل هذا؟
\n- \n
s[:index]— نأخذ جميع العناصر قبل المحذوف (بدون تضمينه). \n s[index+1:]— نأخذ جميع العناصر بعد المحذوف. \n appendيدمج هذين "الجزأين" في شريحة واحدة. \n
هام: هذه الطريقة تغير المصفوفة الأساسية. بعد العملية، سيبقى العنصر 3 فيزيائيًا في الذاكرة (سيتم استبداله فقط إذا أضفت عناصر جديدة). لكنه "اختفى" من الشريحة بالنسبة لك.
الطريقة 2: الحذف حسب الفهرس (بدون الحفاظ على الترتيب) — طريقة سريعة
\n\nإذا كان ترتيب العناصر غير مهم (مثلاً، تعمل مع مجموعة بيانات غير مرتبة)، يمكنك استخدام حيلة "الاستبدال بالعنصر الأخير":
\n\nfunc removeFast(s []int, index int) []int {\n // نستبدل العنصر المحذوف بالعنصر الأخير\n s[index] = s[len(s)-1]\n // نقطع الشريحة، متجاهلين العنصر الأخير\n return s[:len(s)-1]\n}\n\nfunc main() {\n slice := []int{1, 2, 3, 4, 5}\n slice = removeFast(slice, 1) // نحذف العنصر ذا الفهرس 1 (القيمة 2)\n fmt.Println(slice) // [1 5 3 4] — الترتيب مضطرب!\n}\n\n\nلماذا هذا أسرع؟ لأننا لا ننسخ نصف الشريحة. نحن فقط ننقل عنصرًا واحدًا (الأخير) إلى مكان المحذوف ونختصر الشريحة. العملية من درجة O(1) مقابل O(n) في الطريقة الأولى.
\n\nمتى تستخدم: في الحلقات المكثفة، عندما يكون الأداء حرجًا والترتيب غير مهم (مثلاً، عند الحذف من مجموعة كائنات).
\n\nالطريقة 3: الحذف حسب القيمة (أول ظهور)
\n\nغالبًا ما تحتاج إلى البحث عن عنصر وحذفه حسب قيمته، وليس حسب فهرسه. للقيام بذلك، نجد الفهرس أولاً ثم نطبق إحدى الطرق أعلاه.
\n\nfunc removeByValue(s []string, value string) []string {\n for i, v := range s {\n if v == value {\n return append(s[:i], s[i+1:]...)\n }\n }\n return s // إذا لم نجد، نعيد