Warum die Sortierung eines Wörterbuchs nach Wert Kopfschmerzen bereitet (und wie man sie heilt)
\n\nHaben Sie jemals die Situation erlebt: Sie haben ein Dictionary<string, int> mit Dutzenden von Einträgen und müssen diese in absteigender Reihenfolge der Beliebtheit ausgeben? Zum Beispiel eine Liste der häufigsten Wörter in einem Text oder die Top-10-Produkte nach Verkäufen. Scheinbar eine einfache Aufgabe, aber das standardmäßige Dictionary in C# speichert Daten in beliebiger Reihenfolge. Auf Stack Overflow hat die Frage "How do you sort a dictionary by value?" tausende Aufrufe erhalten – und das nicht ohne Grund.
In diesem Tutorial behandeln wir alle legalen Methoden zur Sortierung eines Dictionary nach Wert in C#: vom einfachen LINQ-Hack bis zur Erstellung eines eigenen geordneten Wörterbuchs. Sie erfahren, welche Methode Sie für maximale Leistung und Lesbarkeit des Codes wählen sollten.
\n\nWarum sortiert sich ein Dictionary nicht von selbst?
\n\nBevor wir in den Code eintauchen, lassen Sie uns die Natur von Dictionary<TKey, TValue> verstehen. Dieser Datentyp ist eine Hashtabelle. Er ist optimiert für schnelles Suchen nach Schlüsseln, nicht für die Speicherung von Elementen in einer bestimmten Reihenfolge. Wenn Sie ein Element hinzufügen, landet es basierend auf dem Hash des Schlüssels in einem "Bucket". Es findet keinerlei Sortierung statt.
Wenn Sie eine sortierte Ausgabe benötigen – müssen Sie manuell eingreifen. Die gute Nachricht: C# bietet mehrere elegante Lösungen.
\n\nMethode 1: LINQ – die beliebteste Methode (wie in der Stack Overflow-Antwort)
\n\nDer einfachste und am häufigsten verwendete Ansatz ist die Verwendung von LINQ und der Methode OrderBy oder OrderByDescending. Diese Variante ist ideal, wenn Sie Daten einmalig für die Anzeige oder den Export sortieren müssen.
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// Sortierung nach Wert aufsteigend\nvar sortedAsc = fruits.OrderBy(pair => pair.Value);\n\n// Sortierung nach Wert absteigend\nvar sortedDesc = fruits.OrderByDescending(pair => pair.Value);\n\nConsole.WriteLine("Aufsteigend:");\nforeach (var item in sortedAsc)\n{\n Console.WriteLine($"{item.Key}: {item.Value}");\n}\n\nConsole.WriteLine("\\nAbsteigend:");\nforeach (var item in sortedDesc)\n{\n Console.WriteLine($"{item.Key}: {item.Value}");\n}\n\nErgebnis:
\nAufsteigend:\ngrape: 1\nbanana: 3\napple: 5\norange: 8\n\nAbsteigend:\norange: 8\napple: 5\nbanana: 3\ngrape: 1\n\nWie funktioniert das?
\nOrderBy gibt ein IOrderedEnumerable<KeyValuePair<string, int>> zurück – eine Sequenz, die "träge" sortiert wird (erst beim ersten Durchlauf). Dies ist kein neues Wörterbuch, sondern eine Projektion. Wenn Sie das Ergebnis speichern möchten, konvertieren Sie es mit .ToDictionary() zurück in ein Wörterbuch.
Wichtig: ToDictionary erstellt ein gewöhnliches Dictionary, das wiederum keine Reihenfolge garantiert. Wenn die Reihenfolge entscheidend ist – verwenden Sie SortedDictionary oder eine Liste von Tupeln.
Methode 2: SortedDictionary – wenn die Reihenfolge dauerhaft benötigt wird
\n\nWenn Sie planen, wiederholt auf sortierte Daten zuzugreifen, ist es besser, SortedDictionary zu verwenden. Diese Klasse behält automatisch die Sortierung nach Schlüssel bei. Aber wir benötigen sie nach Wert!
Der Trick: Wir können SortedDictionary nicht direkt zwingen, nach Wert zu sortieren. Aber wir können SortedDictionary mit einem benutzerdefinierten Comparer verwenden oder, einfacher, eine Hilfsklasse erstellen.
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"