كيفية خلط قائمة في C#: دليل شامل للمبتدئين

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

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

ابدأ الدورة

كيفية خلط قائمة في C#: من مبتدئ إلى مستخدم واثق

\n\n

تخيل موقفاً: أنت تكتب برنامجاً لمسابقة، ويجب أن تظهر الأسئلة بترتيب عشوائي. أو ربما تقوم بعمل تطبيق لسحب الجوائز، حيث يحصل كل مشارك على رقم عشوائي. أو ربما تريد فقط أن تعمل قائمة التشغيل الموسيقية بشكل عشوائي، وليس أبجدياً. في كل هذه الحالات، تواجه نفس المهمة: كيفية خلط قائمة (List<T>) في C#؟

\n\n

السؤال شائع جداً لدرجة أنه حصل على آلاف المشاهدات ومئات الإجابات على Stack Overflow. وهذا ليس مفاجئاً - على الرغم من أن المهمة تبدو بسيطة، إلا أن لها مخاطر خفية. في هذه المقالة، سنستعرض ثلاث طرق شائعة لعشوائية القوائم في C#، من الأبسط إلى الأكثر فعالية. ستتعلم كيف يعمل كل طريقة، ومتى تستخدمها، والأهم من ذلك، كيف تتجنب الأخطاء الشائعة.

\n\n

لماذا لا يمكنك ببساطة الفرز عشوائياً؟

\n\n

أول ما يتبادر إلى ذهن المبتدئ: "دعني أفرز القائمة بشكل عشوائي!" يبدو الأمر كالتالي:

\n\n
List<string> myList = new List<string> { "تفاحة", "موز", "كرز", "شمام" };\nRandom rnd = new Random();\nvar shuffled = myList.OrderBy(item => rnd.Next()).ToList();\n
\n\n

الكود يعمل. لكن فقط للوهلة الأولى. المشكلة هي أن Random.Next() يُستدعى مرة واحدة لكل عنصر، وتتم المقارنة بناءً على رقم عشوائي واحد. هذا لا يضمن توزيعاً متساوياً. علاوة على ذلك، يمكن أن يؤدي هذا الأسلوب إلى انحياز (bias) - بعض العناصر قد تظهر في بداية أو نهاية القائمة بشكل متكرر. بالنسبة للتطبيقات الجادة (مثل الحسابات العلمية أو الألعاب)، هذا غير مقبول.

\n\n

لكن لا تتسرع في رفض هذه الطريقة! بالنسبة للمهام البسيطة حيث الدقة ليست حرجة، فهي مقبولة. المهم أن تتذكر حدودها.

\n\n

الطريقة رقم 1: خوارزمية فيشر-يتس (المعروفة أيضاً بـ Knuth Shuffle) - المعيار الذهبي

\n\n

إذا كنت تريد القيام بالأمر بشكل صحيح من المرة الأولى، استخدم خوارزمية فيشر-يتس. هذه هي الطريقة الكلاسيكية لخلط مصفوفة أو قائمة، المستخدمة في البرمجة منذ عام 1938. تعمل بزمن O(n) وذاكرة إضافية O(1) - أي أنها سريعة وفعالة جداً.

\n\n

إليك كيف تبدو في C#:

\n\n
using System;\nusing System.Collections.Generic;\n\npublic static class ListExtensions\n{\n    private static readonly Random rng = new Random();\n\n    public static void Shuffle<T>(this IList<T> list)\n    {\n        int n = list.Count;\n        while (n > 1)\n        {\n            n--;\n            int k = rng.Next(n + 1);\n            T value = list[k];\n            list[k] = list[n];\n            list[n] = value;\n        }\n    }\n}\n
\n\n

كيف يعمل هذا؟

\n
    \n
  • نبدأ من آخر عنصر في القائمة.
  • \n
  • نختار فهرساً عشوائياً من 0 إلى الموضع الحالي.
  • \n
  • نتبادل العنصر في الموضع الحالي مع العنصر في الفهرس العشوائي.
  • \n
  • ننتقل إلى العنصر السابق ونكرر حتى نصل إلى البداية.
  • \n
\n\n

لماذا هذا هو الخيار الأفضل؟

\n
    \n
  • التساوي: كل تبديل للعناصر متساوي الاحتمال.
  • \n
  • الكفاءة: تمريرة واحدة عبر القائمة، لا عمليات زائدة.
  • \n
  • يعمل في المكان: لا ينشئ قوائم جديدة، مما يوفر الذاكرة.
  • \n
  • العالمية: يعمل مع أي نوع IList<T>، بما في ذلك المصفوفات.
  • \n
\n\n

الاستخدام بسيط:

\n\n
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\nnumbers.Shuffle();\n// الآن numbers بترتيب عشوائي\n
\n\n

لاحظ: لقد أعلنا

المدونات

توصيات الكتب