C# LINQ Cheatsheet

6 Kernkonzepte
Die wichtigsten LINQ-Operatoren in C#: Where · Select · OrderBy · GroupBy · Join · Aggregate Language Integrated Query (LINQ) ist ein leistungsstarkes Feature von C# für die Abfrage und Manipulation von Daten in Collections, Datenbanken und XML – mit einer einheitlichen, deklarativen Syntax.

Filterung – Where, OfType, Distinct

Where() · OfType() · Distinct()
// Filterung mit Where var zahlen = new List<int> { 1, 2, 3, 4, 5 }; var gerade = zahlen.Where(x => x % 2 == 0); // {2, 4}

Where filtert eine Sequenz basierend auf einer Bedingung. OfType filtert nach einem bestimmten Typ, Distinct entfernt Duplikate.

Filter-Operatoren

Operator Beschreibung Rückgabetyp
Where(predicate) Filtert nach Bedingung IEnumerable<T>
OfType<T>() Filtert nach Typ IEnumerable<T>
Distinct() Entfernt Duplikate IEnumerable<T>
DistinctBy(key) Entfernt Duplikate nach Schlüssel IEnumerable<T>
Beispiele
// Where mit Lambda
var personen = new List<Person> { /* ... */ };
var erwachsene = personen.Where(p => p.Alter >= 18);
// Mehrere Bedingungen
var filter = personen.Where(p => p.Alter >= 18 && p.Stadt == "Berlin");
// OfType (Filter nach Typ)
object[] mixed = { 42, "Hallo", 3.14, "Welt" };
var strings = mixed.OfType<string>(); // {"Hallo", "Welt"}
// Distinct
int[] zahlen = { 1, 2, 2, 3, 3, 3 };
var unique = zahlen.Distinct(); // {1, 2, 3}
Tipp: LINQ-Abfragen werden lazy ausgeführt – die Filterung erfolgt erst beim Iterieren (z.B. mit ToList() oder foreach).

Projektion – Select, SelectMany

Select() · SelectMany()
// Projektion mit Select var namen = personen.Select(p => p.Name); // IEnumerable var personenInfo = personen.Select(p => new { p.Name, p.Alter });

Select transformiert jedes Element einer Sequenz in ein neues Element. SelectMany flacht verschachtelte Sequenzen ab (eine Ebene).

Beispiele
// Select für Transformation
int[] zahlen = { 1, 2, 3, 4, 5 };
var quadrate = zahlen.Select(x => x * x); // {1, 4, 9, 16, 25}
// Anonyme Typen mit Select
var personen = new List<Person> { /* ... */ };
var result = personen.Select(p => new {
Vorname = p.Vorname,
AlterIn5Jahren = p.Alter + 5
});
// SelectMany (flacht ab)
var listen = new List<List<int>> {
new List<int> { 1, 2 },
new List<int> { 3, 4 }
};
var alle = listen.SelectMany(l => l); // {1, 2, 3, 4}
Tipp: Select ist das Äquivalent zu map() in anderen Sprachen. Es erzeugt eine neue Sequenz mit transformierten Elementen.

Sortierung – OrderBy, ThenBy, Reverse

OrderBy() · OrderByDescending() · ThenBy() · Reverse()
// Sortierung var sortiert = personen.OrderBy(p => p.Alter).ThenBy(p => p.Name); var absteigend = personen.OrderByDescending(p => p.Alter);

OrderBy sortiert aufsteigend, OrderByDescending absteigend. ThenBy ermöglicht sekundäre Sortierkriterien, Reverse kehrt die Reihenfolge um.

Beispiele
// Einfache Sortierung
int[] zahlen = { 5, 2, 8, 1, 9 };
var aufsteigend = zahlen.OrderBy(x => x); // {1, 2, 5, 8, 9}
// Mehrere Sortierkriterien
var personen = new List<Person> { /* ... */ };
var sortiert = personen
.OrderBy(p => p.Stadt)
.ThenBy(p => p.Name)
.ThenByDescending(p => p.Alter);
// Reverse (Reihenfolge umkehren)
var umgekehrt = zahlen.Reverse(); // {9, 1, 8, 2, 5}
// Benutzerdefinierte Sortierung mit IComparer
var customSort = personen.OrderBy(p => p, new PersonComparer());
Tipp: Sortieroperationen sind stabil – Elemente mit gleichen Sortierwerten behalten ihre ursprüngliche Reihenfolge.

Gruppierung – GroupBy, ToLookup

GroupBy() · ToLookup()
// Gruppierung var gruppen = personen.GroupBy(p => p.Stadt); foreach (var gruppe in gruppen) { Console.WriteLine($"Stadt: {gruppe.Key}, Anzahl: {gruppe.Count()}"); }

GroupBy gruppiert Elemente nach einem Schlüssel. ToLookup erstellt eine ILookup-Struktur für schnellen Zugriff auf die Gruppen.

Beispiele
// Einfache Gruppierung
var produkte = new List<Produkt> { /* ... */ };
var nachKategorie = produkte.GroupBy(p => p.Kategorie);
// Gruppierung mit Transformation
var gruppenInfo = produkte.GroupBy(
p => p.Kategorie,
(kategorie, produkte) => new {
Kategorie = kategorie,
Anzahl = produkte.Count(),
Durchschnittspreis = produkte.Average(p => p.Preis)
}
);
// ToLookup (für schnellen Zugriff)
var lookup = personen.ToLookup(p => p.Stadt);
var berliner = lookup["Berlin"]; // Alle Personen aus Berlin
Tipp: GroupBy ist lazy – die Gruppierung erfolgt erst beim Iterieren. ToLookup wird sofort ausgewertet und ist für wiederholte Zugriffe effizienter.

Verknüpfung – Join, GroupJoin, Zip

Join() · GroupJoin() · Zip()
// Join (Inner Join) var joined = personen.Join(adressen, p => p.Id, a => a.PersonId, (p, a) => new { p.Name, a.Stadt });

Join verbindet zwei Sequenzen basierend auf Schlüsseln (Inner Join). GroupJoin erzeugt eine hierarchische Verknüpfung (Left Join). Zip kombiniert zwei Sequenzen paarweise.

Beispiele
// Inner Join
var kunden = new List<Kunde> { /* ... */ };
var bestellungen = new List<Bestellung> { /* ... */ };
var kundenMitBestellungen = kunden.Join(
bestellungen,
k => k.Id,
b => b.KundeId,
(k, b) => new { k.Name, b.Betrag }
);
// GroupJoin (Left Join)
var kundenMitBestellungenGroup = kunden.GroupJoin(
bestellungen,
k => k.Id,
b => b.KundeId,
(k, bestellungen) => new { Kunde = k, Bestellungen = bestellungen }
);
// Zip (paarweise Kombination)
string[] namen = { "Anna", "Ben" };
int[] alters = { 30, 25 };
var kombiniert = namen.Zip(alters, (n, a) => $"{n} ist {a} Jahre alt");
Tipp: Für Datenbankabfragen (Entity Framework) werden LINQ-Operatoren in SQL übersetzt. Join wird zu INNER JOIN, GroupJoin zu LEFT JOIN.

Aggregationen – Sum, Average, Min, Max, Count

Sum() · Average() · Min() · Max() · Count() · Aggregate()
// Aggregationen var summe = zahlen.Sum(); var avg = zahlen.Average(); var max = zahlen.Max(); var count = zahlen.Count(); var produkt = zahlen.Aggregate((a, b) => a * b);

Aggregationsoperatoren berechnen einen einzelnen Wert aus einer Sequenz – Summe, Durchschnitt, Minimum, Maximum, Anzahl oder benutzerdefinierte Aggregate.

Beispiele
// Einfache Aggregationen
double[] preise = { 9.99, 14.99, 19.99, 5.99 };
var gesamt = preise.Sum(); // 50.96
var durchschnitt = preise.Average(); // 12.74
var teuerstes = preise.Max(); // 19.99
var guenstigstes = preise.Min(); // 5.99
var anzahl = preise.Count(); // 4
// Aggregation mit Selektor
var summeAlter = personen.Sum(p => p.Alter);
// Aggregate (benutzerdefinierte Aggregation)
string[] woerter = { "Hallo", "Welt", "LINQ" };
var satz = woerter.Aggregate((a, b) => a + " " + b); // "Hallo Welt LINQ"
// Aggregat mit Startwert
var produkt = zahlen.Aggregate(1, (a, b) => a * b);
// Any / All / Contains
var hasAny = zahlen.Any(x => x > 10); // true/false
var allEven = zahlen.All(x => x % 2 == 0);
var contains3 = zahlen.Contains(3);
Tipp: Any() und All() sind effizienter als Count() > 0, da sie frühzeitig abbrechen. Verwenden Sie FirstOrDefault() für den ersten Treffer.

C# LINQ im Überblick

Where Filterung
Bedingung prüfen
Select Projektion
Transformieren
OrderBy Sortierung
Auf- oder absteigend
GroupBy Gruppierung
Nach Schlüssel
Join Verknüpfung
Inner Join, Left Join
Sum Aggregation
Sum, Avg, Min, Max

Quick Summary

Where
Filterung
Select
Projektion
OrderBy
Sortierung
GroupBy
Gruppierung
Join
Verknüpfung
Sum
Aggregation
list.Where(x => x > 5).Select(x => x * 2).OrderBy(x => x).ToList()