ترتيب قاموس (Dictionary) حسب القيمة في C#: دليل شامل مع أمثلة

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

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

ابدأ الدورة

لماذا ترتيب القاموس (Dictionary) حسب القيمة يمثل تحديًا (وكيفية حله)

\n\n

هل سبق لك أن واجهت موقفًا لديك فيه Dictionary<string, int> يحتوي على عشرات الإدخالات، وتحتاج إلى عرضها بترتيب تنازلي حسب الشعبية؟ على سبيل المثال، قائمة الكلمات الأكثر تكرارًا في نص ما، أو أفضل 10 منتجات من حيث المبيعات. تبدو المهمة بسيطة، لكن Dictionary القياسي في C# يخزن البيانات بترتيب عشوائي. على Stack Overflow، حصد سؤال "How do you sort a dictionary by value?" آلاف المشاهدات — وهذا ليس من قبيل الصدفة.

\n\n

في هذا الدليل التعليمي، سنستعرض جميع الطرق القانونية لترتيب Dictionary حسب القيمة في C#: بدءًا من خدعة LINQ البسيطة وصولاً إلى إنشاء قاموس مرتب خاص بك. ستتعرف على الطريقة المثلى لتحقيق أقصى أداء وسهولة في قراءة الكود.

\n\n

لماذا لا يتم ترتيب Dictionary تلقائيًا؟

\n\n

قبل الغوص في الكود، دعنا نفهم طبيعة Dictionary<TKey, TValue>. هذا النوع من البيانات هو جدول تجزئة (hash table). إنه مُحسَّن لـ البحث السريع باستخدام المفتاح، وليس لتخزين العناصر بترتيب معين. عند إضافة عنصر، يتم وضعه في "سلة" بناءً على قيمة التجزئة للمفتاح. لا يحدث أي ترتيب.

\n\n

إذا كنت بحاجة إلى مخرجات مرتبة — فسيتعين عليك التدخل يدويًا. الخبر السار: توفر C# عدة حلول أنيقة.

\n\n

الطريقة 1: LINQ — الطريقة الأكثر شيوعًا (كما في إجابة Stack Overflow)

\n\n

النهج الأبسط والأكثر استخدامًا هو استخدام LINQ مع دالة OrderBy أو OrderByDescending. هذا الخيار مثالي عندما تحتاج إلى ترتيب البيانات مرة واحدة للعرض أو التصدير.

\n\n
using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nvar fruits = new Dictionary<string, int>\n{\n    {"apple", 5},\n    {"banana", 3},\n    {"orange", 8},\n    {"grape", 1}\n};\n\n// ترتيب تصاعدي حسب القيمة\nvar sortedAsc = fruits.OrderBy(pair => pair.Value);\n\n// ترتيب تنازلي حسب القيمة\nvar sortedDesc = fruits.OrderByDescending(pair => pair.Value);\n\nConsole.WriteLine("ترتيب تصاعدي:");\nforeach (var item in sortedAsc)\n{\n    Console.WriteLine($"{item.Key}: {item.Value}");\n}\n\nConsole.WriteLine("\\nترتيب تنازلي:");\nforeach (var item in sortedDesc)\n{\n    Console.WriteLine($"{item.Key}: {item.Value}");\n}
\n\n

النتيجة:

\n
ترتيب تصاعدي:\ngrape: 1\nbanana: 3\napple: 5\norange: 8\n\nترتيب تنازلي:\norange: 8\napple: 5\nbanana: 3\ngrape: 1
\n\n

كيف يعمل هذا؟

\n

تقوم OrderBy بإرجاع IOrderedEnumerable<KeyValuePair<string, int>> — وهي سلسلة يتم ترتيبها "بكسل" (فقط عند التكرار الأول). هذا ليس قاموسًا جديدًا، بل إسقاط (projection). إذا كنت بحاجة إلى حفظ النتيجة، قم بتحويلها مرة أخرى إلى قاموس باستخدام .ToDictionary().

\n\n

ملاحظة مهمة: ToDictionary ينشئ Dictionary عاديًا لا يضمن الترتيب مرة أخرى. إذا كان الترتيب ضروريًا — استخدم SortedDictionary أو قائمة من المجموعات (tuples).

\n\n

الطريقة 2: SortedDictionary — عندما تحتاج الترتيب باستمرار

\n\n

إذا كنت تخطط للوصول المتكرر إلى البيانات المرتبة، فمن الأفضل استخدام SortedDictionary. هذه الفئة تحافظ تلقائيًا على الترتيب حسب المفتاح. لكننا نحتاج الترتيب حسب القيمة!

\n\n

الحيلة: لا يمكننا جعل SortedDictionary يرتب حسب القيمة مباشرة. لكن يمكننا استخدام SortedDictionary مع مقارن مخصص (custom comparer)، أو ببساطة إنشاء فئة مساعدة.

\n\n
using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nvar fruits = new Dictionary<string, int>\n{\n    {"apple", 5},\n    {"banana", 3},\n    {"orange", 8},\n    {"grape"

المدونات

توصيات الكتب