Menu
flag Ar iconالعربيةdown icon

المجموعات Set في Golang: map[T]struct{} والعمليات ومجموعة عامة

لا تملك Go نوع مجموعة مدمجًا. الأسلوب المعتاد خريطة بقيم من البنية الفارغة. تعلّم الإضافة والفحص والحذف، والاتحاد والتقاطع والفرق، وكيف تكتب نوع Set عامًا صغيرًا.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

الأسلوب المعتاد: خريطة بقيم فارغة

لا تملك Go كلمة set ولا مجموعة في المكتبة القياسية. الخريطة التي مفاتيحها العناصر وقيمها لا تحمل شيئًا تؤدّي المهمة.

struct{} هو نوع البنية الفارغة وstruct{}{} قيمته الوحيدة. يشغل صفر بايت، فتخزّن الخريطة المفاتيح ولا شيء غيرها.

كل قواعد الخرائط تنطبق: يجب أن تكون المفاتيح قابلة للمقارنة، وترتيب المرور عشوائي، والخريطة nil تسبّب panic عند الكتابة، والكتابات المتزامنة تحتاج قفلًا. تشرح صفحة الخرائط كلًا منها.

map[T]struct{} أم map[T]bool

الكتابة الشائعة الأخرى هي map[T]bool. تُقرأ أفضل لأن المفتاح المفقود يعيد false:

seen := map[string]bool{}
seen["a"] = true
if seen["a"] { ... }

المقابل:

map[T]struct{}map[T]bool
حجم القيمة0 بايتبايت واحد (مع المحاذاة)
فحص العضوية_, ok := s[k]s[k]
الالتباسلا يوجدs[k] = false حالة ثالثة

الصف الثالث هو السبب الحقيقي لتفضيل كثير من قواعد الشيفرة البنية الفارغة: مع bool سيكتب أحدهم يومًا s[k] = false فيتوقّف len(s) عن أن يكون عدد الأعضاء. وللمجموعات الصغيرة لا يهمّ فرق الذاكرة.

إزالة التكرار من شريحة

أشيع استخدام للمجموعة هو إزالة التكرار. يحتفظ هذا بأول ظهور لكل قيمة ويحافظ على الترتيب:

المخرجات:

[b a c]
[3 1 2]
[1 2 3]

الاتحاد والتقاطع والفرق

جبر المجموعات بضع حلقات. مرّ على المجموعة الأصغر عند فحص العضوية في الأخرى، لأن كل بحث يستغرق وقتًا ثابتًا في المتوسّط.

sorted موجودة فقط لجعل المخرجات ثابتة. طباعة مجموعة بالمرور عليها تعطي ترتيبًا مختلفًا في كل تشغيل. تحتاج maps.Keys وslices.Sorted إلى Go 1.23.

النوع المسمّى مثل type set map[string]struct{} يبقى خريطة: تفهرسه وتمرّ عليه بـ range وتحذف منه بـ delete بالطريقة نفسها، ويمكنك تعليق توابع عليه.

نوع Set عام صغير

مع الأنواع العامة (Go 1.18) يغطّي نوع واحد كل أنواع العناصر القابلة للمقارنة. وهذا يكفي معظم البرامج:

تغليف الخريطة في بنية يخفي ضجيج struct{}{} ويضمن أن دالة البناء تنشئ الخريطة، فيزول panic الخريطة nil. لا يمكن أن تكون Sorted تابعًا: لا يستطيع التابع تعريف معاملات نوع خاصة به أو تشديد قيد comparable الخاص بالنوع، والترتيب يحتاج cmp.Ordered. تشرح صفحة الأنواع العامة القيود.

إذا احتجت مجموعة كاملة الميزات (صيغ آمنة للخيوط، وعمليات كثيرة)، توجد حزم خارجية مثل github.com/deckarep/golang-set. لكن في معظم الشيفرات يستخدم مبرمجو Go أسلوب الخريطة أو نوعًا من 30 سطرًا مثل هذا.

مجموعات من البنى

أي نوع قابل للمقارنة يمكن أن يكون عنصرًا، بما في ذلك البنى ذات الحقول القابلة للمقارنة. وهذا يجعل فحوص "هل رأيت هذا الزوج" مباشرة:

type edge struct{ from, to string }
visited := map[edge]struct{}{}
visited[edge{"a", "b"}] = struct{}{}

لا يمكن أن تكون الشرائح والخرائط عناصر مجموعة. لتتبّع الشرائح الفريدة، حوّل كلًا منها إلى مفتاح قابل للمقارنة أولًا، مثل مصفوفة ثابتة الحجم، أو نص مبني بـ fmt.Sprint.

أخطاء شائعة

  • نسيان التهيئة. var s map[string]struct{} قيمتها nil؛ وأول إضافة تسبّب panic.
  • طباعة مجموعة وتوقّع مخرجات ثابتة. رتّب الأعضاء أولًا.
  • استخدام map[T]bool وتخزين false. عندها لا يعدّ len الأعضاء. استخدم delete للحذف.

الأسئلة الشائعة

هل تملك Go نوع مجموعة (set)؟

لا. لا توجد مجموعة في المكتبة القياسية. الأسلوب المعتاد خريطة لا تحمل قيمها أي معلومة: map[string]struct{}. الإضافة s[k] = struct{}{}، وفحص العضوية _, ok := s[k]، والحذف delete(s, k)، والحجم len(s).

هل أستخدم map[T]bool أم map[T]struct{} كمجموعة في Go؟

تجعل map[T]struct{} النية صريحة وقيمها تشغل صفر بايت. أما map[T]bool فتُقرأ بشكل أطبع (if seen[x]) لأن المفتاح المفقود يعيد false. كلاهما صحيح؛ والفرق في الذاكرة لا يهمّ إلا في المجموعات الكبيرة جدًا. اختر واحدًا والتزم به.

كيف أزيل التكرار من شريحة في Go؟

للإبقاء على أول ظهور بالترتيب، مرّ في حلقة وتتبّع القيم التي رأيتها في map[T]struct{}، وألحق فقط ما لم تره. وإذا لم يكن الترتيب مهمًا، فرتّب واحذف التكرارات المتجاورة: slices.Sort(s); s = slices.Compact(s).

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن