CodeGym /Kurse /C# SELF /Sortieren von Kollektionen

Sortieren von Kollektionen

C# SELF
Level 29 , Lektion 2
Verfügbar

1. Einführung

Wenn du schon mal eine Schublade voller Socken hattest und ein Paar gesucht hast, kennst du das Sortierproblem. Wenn alles durcheinander liegt, wird das Finden zur Quest. Mit Kollektionen im Programmieren ist es genau das Gleiche.

Sortieren bedeutet, die Elemente einer Kollektion nach einem bestimmten Kriterium zu ordnen (zum Beispiel alphabetisch, nach Wert, Datum usw.). Das ist wichtig für:

  • Anzeige von Daten für den User (niemand mag Chaos).
  • Einfacheres Suchen (z.B. Binary Search geht nur bei sortierten Kollektionen).
  • Vergleiche, Reports, Export und andere Aktionen.

Die Millionenfrage: "Und wenn ich nur fünf Elemente habe, muss ich dann sortieren?" – Theoretisch nein, aber sobald aus fünf fünfhundert oder fünftausend werden, kommst du um Automatisierung nicht herum.

In .NET gibt es zwei Hauptansätze zum Sortieren:

  • Die Original-Kollektion verändern (z.B. List<T> mit der Sort-Methode sortieren).
  • Eine neue, sortierte Kopie der Kollektion erstellen (z.B. Array klonen und dann sortieren).

Listen sortieren mit der Methode .Sort()

Die Methode Sort() gibt's bei der Klasse List<T>, weil diese das Interface IList<T> implementiert und damit Zugriff per Index und das Ändern der Reihenfolge erlaubt.

Beispiel – Zahlen aufsteigend sortieren:


using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var numbers = new List<int> { 5, 2, 9, 1, 5, 6 };
        numbers.Sort();
        Console.WriteLine("Sortierung aufsteigend:");
        foreach(var number in numbers)
        {
            Console.Write($"{number} "); // 1 2 5 5 6 9
        }
    }
}

Hier wird "in place" sortiert: Die Original-Liste numbers wird verändert, die Elemente werden umsortiert.

Strings sortieren

Sortieren klappt auch super mit Strings:


var words = new List<string> { "apelsin", "yabloko", "banan", "grusha" };
words.Sort();
Console.WriteLine(string.Join(", ", words)); // apelsin, banan, grusha, yabloko

Fun Fact: Standardmäßig wird nach Unicode sortiert, nicht nach "menschlichem" Alphabet (vor allem bei verschiedenen Sprachen, also aufpassen bei mehrsprachigen Apps).

2. Sortieren nach eigenen Regeln

Manchmal reicht die "Standard"-Sortierung nicht. Zum Beispiel willst du User nicht nach Name, sondern nach Alter oder Registrierungsdatum sortieren.

Sortieren mit Lambda-Ausdruck (Methode Sort(Comparison<T>))

Die Sort-Methode kann man so aufrufen, dass man eine eigene Vergleichsfunktion übergibt.

User nach Alter sortieren:


class User
{
    public string Name { get; set; }
    public int Age { get; set; }
}

// ...

var users = new List<User>
{
    new User { Name = "Alisa", Age = 30 },
    new User { Name = "Bob", Age = 25 },
    new User { Name = "Eva", Age = 35 }
};

users.Sort((u1, u2) => u1.Age.CompareTo(u2.Age));

foreach (var user in users)
{
    Console.WriteLine($"{user.Name}: {user.Age}");
}
// Ausgabe:
// Bob: 25
// Alisa: 30
// Eva: 35

Wie funktioniert das? Das Lambda (u1, u2) => u1.Age.CompareTo(u2.Age) gibt eine negative Zahl zurück, wenn u1 jünger ist, eine positive wenn älter, und 0, wenn das Alter gleich ist.

Das Interface IComparer<T> verwenden

Manchmal will man die Sortierregel in eine eigene Klasse auslagern, z.B. wenn man viele Kollektionen und komplexe Logik hat.


class UserAgeComparer : IComparer<User>
{
    public int Compare(User x, User y)
    {
        return x.Age.CompareTo(y.Age);
    }
}

// ...

var users = new List<User>{ /* ... */ };
users.Sort(new UserAgeComparer()); // jetzt nach Alter sortiert

Das ist praktisch, wenn man die Sortierung an mehreren Stellen braucht oder viele Sortierarten hat.

Sortieren nach mehreren Feldern von Hand

Wenn einige User das gleiche Alter haben, du aber innerhalb der Altersgruppe nach Name sortieren willst:


users.Sort((u1, u2) => {
    int ageCompare = u1.Age.CompareTo(u2.Age);
    if (ageCompare != 0)
        return ageCompare;
    else
        return u1.Name.CompareTo(u2.Name);
});

Jetzt wird erst nach Alter, dann nach Name sortiert.

3. Sortieren einer Kopie der Kollektion (ohne das Original zu ändern)

Wenn du die Original-Liste nicht verändern willst, kopiere sie vor dem Sortieren:


var copy = new List<int>(numbers);
copy.Sort();

Für eigene Objekte genauso:


var usersCopy = new List<User>(users);
usersCopy.Sort((a, b) => a.Age.CompareTo(b.Age));

4. Arrays sortieren

Mit Arrays (T[]) ist es auch easy:


int[] numbers = { 4, 2, 9, 7 };
Array.Sort(numbers); // das Original-Array wird verändert

Für "eigene" Sortierung:


Array.Sort(numbers, (a, b) => b.CompareTo(a)); // absteigend sortieren

Achtung: Array.Sort verändert das Original-Array und gibt kein neues zurück. Wenn du das Original behalten willst, kopiere das Array vorher:


int[] oldNumbers = { 3, 2, 1 };
int[] copy = (int[])oldNumbers.Clone();
Array.Sort(copy);

5. "Sortieren" von Dictionaries (Dictionary<TKey, TValue>)

Dictionary<TKey, TValue> ist von Natur aus ungeordnet (d.h. die Reihenfolge beim Durchlaufen ist nicht garantiert). Aber manchmal will man "sortierte Paare" bekommen.

Um sortierte Keys oder Values zu bekommen, erstelle eine Liste, kopiere die Paare rein und sortiere wie du willst:


var dict = new Dictionary<string, int>
{
    { "yabloko", 2 },
    { "apelsin", 5 },
    { "grusha", 3 }
};

// Nach Key sortieren:
var keyValueList = new List<KeyValuePair<string, int>>(dict);
keyValueList.Sort((a, b) => a.Key.CompareTo(b.Key));
foreach (var kv in keyValueList)
{
    Console.WriteLine($"{kv.Key}: {kv.Value}");
}

// Nach Value sortieren:
keyValueList.Sort((a, b) => a.Value.CompareTo(b.Value));
foreach (var kv in keyValueList)
{
    Console.WriteLine($"{kv.Key}: {kv.Value}");
}

Wenn du eine sortierte Liste von Keys oder Values brauchst:


var sortedKeys = new List<string>(dict.Keys);
sortedKeys.Sort();

var sortedValues = new List<int>(dict.Values);
sortedValues.Sort();

Aber denk dran: Die Dictionary-Struktur bleibt unverändert – du bekommst nur eine sortierte Aufzählung. In .NET 9 kommt OrderedDictionary<TKey, TValue>, der die Reihenfolge der Elemente speichert. Braucht man nicht oft, aber manchmal ist es praktisch.

6. Nützliche Besonderheiten

Muss man das Vergleichs-Interface implementieren?

Ganz einfach: Wenn deine Objekte "wissen" sollen, wie sie sich vergleichen (z.B. nach Datum oder Name), implementiere das Interface IComparable<T>.


class Product : IComparable<Product>
{
    public string Name { get; set; }
    public decimal Price { get; set; }

    public int CompareTo(Product other)
    {
        return Price.CompareTo(other.Price);
    }
}

Jetzt kannst du:


var products = new List<Product> { /* ... */ };
products.Sort(); // sortiert nach Preis

Wenn dir der Standardvergleich nicht passt – nutze IComparer<T> oder gib ein Lambda an, wie oben gezeigt.

User-Liste alphabetisch sortieren

Angenommen, wir haben in der App eine User-Liste:


List<string> users = new List<string> { "Viktor", "Anna", "Ekaterina", "Boris" };
users.Sort(); // jetzt ist users sortiert: Anna, Boris, Ekaterina, Viktor

Aufgaben nach Dringlichkeit sortieren


class Task
{
    public string Title { get; set; }
    public int Priority { get; set; } // 1 - dringend, 2 - wichtig, 3 - kann warten
}

var todo = new List<Task>
{
    new Task { Title = "Hausaufgaben machen", Priority = 2 },
    new Task { Title = "Brot kaufen", Priority = 1 },
    new Task { Title = "Serie schauen", Priority = 3 }
};

todo.Sort((a, b) => a.Priority.CompareTo(b.Priority));

foreach (var task in todo)
    Console.WriteLine($"{task.Priority}: {task.Title}");

Vergleich der Sortiermethoden

Kollektion Wird in place verändert? Methode zum Sortieren Kann man eine Regel angeben?
List<T>
Ja
Sort()
Ja: Lambda oder IComparer
T[]
Ja
Array.Sort()
Ja: Lambda oder IComparer
Dictionary<TKey, TValue>
Nein – (Liste erstellen und sortieren) Ja: über Lambda oder IComparer

7. Typische Fehler und Besonderheiten beim Sortieren

Sortieren in place – verändert die Original-Kollektion! Wenn die Originaldaten nicht verändert werden sollen – kopiere sie vorher.

Versuch, eine unveränderbare Kollektion zu sortieren (z.B. ReadOnlyCollection<T>) führt zu einem Laufzeitfehler.

String-Vergleich ist je nach Kultur unterschiedlich: Das Sortieren von Strings (vor allem mit Kyrillisch, Umlauten usw.) kann je nach Locale anders sein. Für korrekte Sortierung nutze Comparer.Create(...) mit der gewünschten Kultur.

Sortieren von Dictionaries verändert deren Struktur nicht – du bekommst immer eine neue Sequenz von Paaren (oder eine neue Liste).

Für komplexe Sortierung nutze das Interface IComparer<T> mit deiner Logik.

Hier ein Beispiel für falsches Sortieren (klassische Stolperfalle):


var numbers = new List<int> { 1, 2, 3 };
var sorted = numbers.Sort(); // FEHLER: Sort() gibt void zurück!

Richtig:


numbers.Sort(); // verändert numbers in place

// Wenn du eine neue Kollektion willst:
var sorted = new List<int>(numbers);
sorted.Sort();
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION