Skip to main content
Eine Liste ist eine geordnete Sammlung von Werten desselben Typs.
let numbers = [1; 2; 3; 4; 5]         // int list
let names = ["Anna"; "Ben"; "Carla"]  // string list

Erstellung

let numbers = [1; 2; 3; 4]
let emptyList = []
let emptyNumbers: int list = []
let numbers = [1 .. 10]
let evenNumbers = [2 .. 2 .. 10]

Zugriff

Man kann mit list[index] auf ein Element zugreifen.
let numbers = [10; 20; 30; 40]

let first = numbers[0]
let second = numbers[1]
Wenn der Index nicht existiert, gibt es einen Fehler.

Head und Tail

List.head gibt das erste Element einer Liste zurück.
let numbers = [10; 20; 30]
let first = List.head numbers
Achtung: Bei einer leeren Liste gibt List.head einen Fehler.
List.head [] // Fehler

Sauberer ist oft Pattern Matching:
let getFirst list =
    match list with
    | [] -> None
    | x :: _ -> Some x

List.tail gibt die Liste ohne das erste Element zurück.
let numbers = [10; 20; 30]
let rest = List.tail numbers
Auch hier gilt: Bei einer leeren Liste gibt es einen Fehler.
List.tail [] // Fehler

Sauber mit Pattern Matching:
let getTail list =
    match list with
    | [] -> []
    | _ :: xs -> xs

Cons Operator ::

Der Cons Operator :: fügt ein Element vorne an eine Liste an.
let numbers = [2; 3; 4]
let newNumbers = 1 :: numbers
Wichtig: Das Element links muss den gleichen Typ haben wie die Elemente der Liste.

Der Cons Operator wird auch oft in Pattern Matching verwendet:
let describe list =
    match list with
    | [] -> "Die Liste ist leer"
    | x :: xs -> $"Erstes Element: {x}, Rest: {xs}"

describe [1; 2; 3]

Append Operator @

Der Append Operator @ verbindet zwei Listen.
let list1 = [1; 2; 3]
let list2 = [4; 5; 6]

let combined = list1 @ list2

List Comprehensions

List Comprehensions sind eine kompakte Möglichkeit, Listen zu erzeugen.
[ for x in collection do yield expression ]
Beispiel:
let squares = [ for x in 1 .. 5 do yield x * x ]

Mit Bedingung

let evenNumbers =
    [ for x in 1 .. 10 do
        if x % 2 = 0 then
            yield x ]

Mehrere yield

Man kann pro Durchlauf mehrere Werte erzeugen.
let numbers =
    [ for x in 1 .. 3 do
        yield x
        yield x * 10 ]

yield!

yield! fügt eine ganze Liste in die neue Liste ein.
let values =
    [ for x in 1 .. 3 do
        yield! [x; x * x] ]

Listenfunktionen

List.map

List.map verändert jedes Element einer Liste nach einer Regel.
let numbers = [1; 2; 3; 4]

let doubled =
    numbers |> List.map (fun x -> x * 2)


let names = ["anna"; "ben"; "carla"]

let upperNames =
    names |> List.map (fun name -> name.ToUpper())

        
type Student = {
    Name: string
    Grade: float
}

let students = [
    { Name = "Anna"; Grade = 5.5 }
    { Name = "Ben"; Grade = 4.0 }
    { Name = "Carla"; Grade = 3.5 }
]

let names =
    students |> List.map (fun student -> student.Name)

List.filter

List.filter behält nur Elemente, die eine Bedingung erfüllen.
let numbers = [1; 2; 3; 4; 5; 6]

let evenNumbers =
    numbers |> List.filter (fun x -> x % 2 = 0)
    

let grades = [5.5; 4.0; 3.5; 6.0; 2.5]

let passedGrades =
    grades |> List.filter (fun grade -> grade >= 4.0)

let passedStudents =
    students |> List.filter (fun student -> student.Grade >= 4.0)

List.length

List.length gibt die Anzahl Elemente zurück.
let numbers = [10; 20; 30]
let count = numbers |> List.length

let names = ["Anna"; "Ben"; "Carla"; "Daniel"]
let amount = names |> List.length

let empty = [] |> List.length

List.sum

List.sum addiert alle Elemente einer numerischen Liste.
let numbers = [1; 2; 3; 4]
let total = numbers |> List.sum

let prices = [10.50; 20.0; 5.25]
let totalPrice = prices |> List.sum

List.sumBy

List.sumBy berechnet zuerst pro Element einen Wert und summiert diese Werte danach.
type Product = {
    Name: string
    Price: float
    Amount: int
}

let products = [
    { Name = "Book"; Price = 20.0; Amount = 2 }
    { Name = "Pen"; Price = 2.5; Amount = 4 }
    { Name = "Bag"; Price = 50.0; Amount = 1 }
]

let total =
    products |> List.sumBy (fun product -> product.Price * float product.Amount)

List.min und List.max

Gibt das kleinste bzw. das grösste Element zurück.
let numbers = [5; 2; 9; 1; 7]
let minimum = numbers |> List.min
let maximum = numbers |> List.max
Achtung: Bei einer leeren Liste gibt es einen Fehler.

List.minBy und List.maxBy

List.minBy gibt das Element zurück, bei dem ein berechneter Wert am kleinsten ist.
let cheapestProduct =
    products |> List.minBy (fun product -> product.Price)
List.maxBy gibt das Element zurück, bei dem ein berechneter Wert am grössten ist.
let mostExpensiveProduct =
    products |> List.maxBy (fun product -> product.Price)

List.rev

List.rev dreht die Reihenfolge einer Liste um. Die ursprüngliche Liste wird nicht verändert.
let numbers = [1; 2; 3; 4]
let reversed =
    numbers |> List.rev
    
let names = ["Anna"; "Ben"; "Carla"]
let reversedNames =
    names |> List.rev

List.sort

List.sort sortiert eine Liste aufsteigend.
let numbers = [5; 1; 9; 2]
let sorted =
    numbers |> List.sort
    
let names = ["Carla"; "Anna"; "Ben"]
let sortedNames =
    names |> List.sort

List.sortBy

List.sortBy sortiert nach einem berechneten Wert.
let studentsByGrade =
    students |> List.sortBy (fun student -> student.Grade)
    
let studentsByName =
    students |> List.sortBy (fun student -> student.Name)

List.sortDescending

List.sortDescending sortiert eines Liste absteigend.
let numbers = [5; 1; 9; 2]
let sortedDescending =
    numbers |> List.sortDescending
    
let names = ["Carla"; "Anna"; "Ben"]
let sortedNames =
    names |> List.sortDescending

List.sortDescendingBy

let studentsBestFirst =
    students |> List.sortByDescending (fun student -> student.Grade)

List.zip

List.zip verbindet zwei Listen elementweise zu Tupeln.
let names = ["Anna"; "Ben"; "Carla"]
let grades = [5.5; 4.0; 3.5]

let combined =
    List.zip names grades
Wenn die Listen unterschiedlich lang sind, gibt List.zip einen Fehler.

List.forAll

List.forall prüft, ob alle Elemente eine Bedingung erfüllen.
let grades = [5.0; 4.5; 6.0]

let allPassed =
    grades |> List.forall (fun grade -> grade >= 4.0)

List.exists

List.exists prüft, ob mindestens ein Element eine Bedingung erfüllt.
let grades = [5.0; 3.5; 4.5]

let hasFailedGrade =
    grades |> List.exists (fun grade -> grade < 4.0)

List.reduce

List.reduce fasst eine Liste zu einem einzelnen Wert zusammen.
let numbers = [1; 2; 3; 4]
let total =
    numbers |> List.reduce (fun acc x -> acc + x)
    
let maximum =
    numbers |> List.reduce (fun acc x -> if x > acc then x else acc)
    
let words = ["F#"; "ist"; "cool"]
let sentence =
    words |> List.reduce (fun acc word -> acc + " " + word)
Wichtig: reduce nimmt das erste Element als Startwert. Darum funktioniert reduce nicht mit einer leeren Liste:
[] |> List.reduce (fun acc x -> acc + x) // Fehler

List.fold

List.fold ist ähnlich wie reduce, aber man gibt einen Startwert mit.
let numbers = [1; 2; 3; 4]
let total =
    numbers |> List.fold (fun acc x -> acc + x) 0

Unterschied zwischen reduce und fold

List.reduce nimmt das erste Listenelement als Startwert, während List.fold einen eigenen Startwert bekommt.
[1; 2; 3] |> List.reduce (fun acc x -> acc + x) // Startet mit 1
[1; 2; 3] |> List.fold (fun acc x -> acc + x) 0 // Startet mit 0
Deshalb funktioniert fold auch mit leeren Listen im Gegensatz zu reduce, wo ein Fehler geworfen wird.
[] |> List.fold (fun acc x -> acc + x) 0
Nur fold kann z.B. aus einer int list einen string machen.
let numbers = [1; 2; 3]

let text =
    numbers |> List.fold (fun acc x -> acc + string x) ""

List.foldBack

List.foldBack läuft von rechts nach links durch die Liste.
let numbers = [1; 2; 3]
let result =
    List.foldBack (fun x acc -> acc + string x) numbers ""

Kombination mehrerer Funktionen

In F# kombiniert man Listenfunktionen oft mit der Pipe |>.
// Gerade Zahlen verdoppeln und summieren
let numbers = [1; 2; 3; 4; 5; 6]

let result =
    numbers
    |> List.filter (fun x -> x % 2 = 0)
    |> List.map (fun x -> x * 2)
    |> List.sum
    


type Student = {
    Name: string
    Grade: float
}

let students = [
    { Name = "Anna"; Grade = 5.5 }
    { Name = "Ben"; Grade = 4.0 }
    { Name = "Carla"; Grade = 3.5 }
    { Name = "Daniel"; Grade = 6.0 }
]

// Alle bestandenen Schülernamen sortiert
let passedNames =
    students
    |> List.filter (fun student -> student.Grade >= 4.0)
    |> List.sortBy (fun student -> student.Name)
    |> List.map (fun student -> student.Name)
xs = [2; 3] { Name = "Anna"; Grade = 5.5 }
{ Name = "Ben"; Grade = 4.0 }
]
{ Name = "Carla"; Grade = 3.5 }
{ Name = "Ben"; Grade = 4.0 }
{ Name = "Anna"; Grade = 5.5 }
]