Teilen über


Listet

Eine Liste in F# ist eine sortierte, unveränderliche Reihe von Elementen desselben Typs. Verwenden Sie die Funktionen im Listenmodul, um grundlegende Vorgänge für Listen auszuführen.

Erstellen und Initialisieren von Listen

Sie können eine Liste definieren, indem Sie die Elemente explizit auflisten, getrennt durch Semikolons und in eckige Klammern eingeschlossen, wie in der folgenden Codezeile dargestellt.

let list123 = [ 1; 2; 3 ]

Sie können auch Zeilenumbrüche zwischen Elementen einfügen, in diesem Fall sind die Semikolons optional. Die letztere Syntax kann zu besser lesbarem Code führen, wenn die Initialisierungsausdrücke des Elements länger sind oder wenn Sie einen Kommentar für jedes Element einfügen möchten.

let list123 = [ 1; 2; 3 ]

Normalerweise müssen alle Listenelemente denselben Typ aufweisen. Eine Ausnahme besteht darin, dass eine Liste, in der die Elemente als Basistyp angegeben werden, Elemente aufweisen kann, die abgeleitete Typen sind. Dies ist also akzeptabel, da beide Button und CheckBox abgeleitet von Control.

let myControlList: Control list = [ new Button(); new CheckBox() ]

Sie können Listenelemente auch mithilfe eines Bereichs definieren, der durch ganze Zahlen getrennt durch den Bereichsoperator (..), wie im folgenden Code dargestellt.

let list1 = [ 1..10 ]

Eine leere Liste wird durch ein Paar eckige Klammern mit nichts dazwischen angegeben.

// An empty list.
let listEmpty = []

Sie können auch einen Sequenzausdruck verwenden, um eine Liste zu erstellen. Weitere Informationen finden Sie unter Sequenzausdrücke . Mit dem folgenden Code wird beispielsweise eine Liste von Quadraten ganzzahliger Zahlen von 1 bis 10 erstellt.

let listOfSquares = [ for i in 1..10 -> i * i ]

Operatoren für das Arbeiten mit Listen

Sie können Elemente an eine Liste anfügen, indem Sie den :: Operator "Cons" verwenden. Wenn list1 dies der Folgende Code ist [2; 3; 4], erstellt list2 der folgende Code als [100; 2; 3; 4].

let list2 = 100 :: list1

Sie können Listen verketten, die kompatible Typen aufweisen, indem Sie den @ Operator wie im folgenden Code verwenden. Ist list1 dies [2; 3; 4][100; 2; 3; 4]der list2 Fall, erstellt list3 dieser Code als [2; 3; 4; 100; 2; 3; 4].

let list3 = list1 @ list2

Funktionen zum Ausführen von Vorgängen in Listen sind im Listenmodul verfügbar.

Da Listen in F# unveränderlich sind, generieren alle Änderungsvorgänge neue Listen, anstatt vorhandene Listen zu ändern.

Listen in F# werden als singly verknüpfte Listen implementiert, was bedeutet, dass Vorgänge, die nur auf den Kopf der Liste zugreifen, O(1) sind und der Elementzugriff O(n) ist.

Eigenschaften

Der Listentyp unterstützt die folgenden Eigenschaften:

Eigentum Typ BESCHREIBUNG
Head 'T Das erste Element.
Leer 'T list Eine statische Eigenschaft, die eine leere Liste des entsprechenden Typs zurückgibt.
IsEmpty bool true wenn die Liste keine Elemente enthält.
Element 'T Das Element am angegebenen Index (nullbasiert).
Länge int Die Anzahl der Elemente.
Tail- 'T list Die Liste ohne das erste Element.

Im Folgenden sind einige Beispiele für die Verwendung dieser Eigenschaften aufgeführt.

let list1 = [ 1; 2; 3 ]

// Properties
printfn "list1.IsEmpty is %b" (list1.IsEmpty)
printfn "list1.Length is %d" (list1.Length)
printfn "list1.Head is %d" (list1.Head)
printfn "list1.Tail.Head is %d" (list1.Tail.Head)
printfn "list1.Tail.Tail.Head is %d" (list1.Tail.Tail.Head)
printfn "list1.Item(1) is %d" (list1.Item(1))

Verwenden von Listen

Durch die Programmierung mit Listen können Sie komplexe Vorgänge mit einer kleinen Menge code ausführen. In diesem Abschnitt werden allgemeine Vorgänge in Listen beschrieben, die für die funktionale Programmierung wichtig sind.

Rekursion mit Listen

Listen eignen sich eindeutig für rekursive Programmiertechniken. Erwägen Sie einen Vorgang, der für jedes Element einer Liste ausgeführt werden muss. Sie können dies rekursiv ausführen, indem Sie auf der Kopfzeile der Liste arbeiten und dann den Tail der Liste übergeben, bei der es sich um eine kleinere Liste handelt, die aus der ursprünglichen Liste ohne das erste Element besteht, wieder auf die nächste Rekursionsebene zurück.

Um eine solche rekursive Funktion zu schreiben, verwenden Sie den Cons-Operator (::) im Musterabgleich, mit dem Sie den Kopf einer Liste vom Schwanz trennen können.

Das folgende Codebeispiel zeigt, wie Musterabgleich verwendet wird, um eine rekursive Funktion zu implementieren, die Vorgänge in einer Liste ausführt.

let rec sum list =
    match list with
    | head :: tail -> head + sum tail
    | [] -> 0

Der vorherige Code eignet sich gut für kleine Listen, aber für größere Listen könnte er den Stapel überlaufen. Der folgende Code verbessert diesen Code mithilfe eines Akkumulatorarguments, einer Standardtechnik für die Arbeit mit rekursiven Funktionen. Die Verwendung des Akkumulatorarguments macht die Funktion tail rekursiv, was Stapelplatz spart.

let sum list =
    let rec loop list acc =
        match list with
        | head :: tail -> loop tail (acc + head)
        | [] -> acc

    loop list 0

Die Funktion ist eine rekursive Funktion RemoveAllMultiples , die zwei Listen akzeptiert. Die erste Liste enthält die Zahlen, deren Vielfache entfernt werden, und die zweite Liste ist die Liste, aus der die Nummern entfernt werden sollen. Der Code im folgenden Beispiel verwendet diese rekursive Funktion, um alle Nicht-Primzahlen aus einer Liste zu entfernen und eine Liste der Primzahlen als Ergebnis zu verlassen.

let IsPrimeMultipleTest n x = x = n || x % n <> 0

let rec RemoveAllMultiples listn listx =
    match listn with
    | head :: tail -> RemoveAllMultiples tail (List.filter (IsPrimeMultipleTest head) listx)
    | [] -> listx


let GetPrimesUpTo n =
    let max = int (sqrt (float n))
    RemoveAllMultiples [ 2..max ] [ 1..n ]

printfn "Primes Up To %d:\n %A" 100 (GetPrimesUpTo 100)

Die Ausgabe lautet wie folgt:

Primes Up To 100:
[2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37; 41; 43; 47; 53; 59; 61; 67; 71; 73; 79; 83; 89; 97]

Modulfunktionen

Das Listenmodul stellt Funktionen bereit, die auf die Elemente einer Liste zugreifen. Das Kopfelement ist am schnellsten und am einfachsten zugänglich. Verwenden Sie die Eigenschaft "Head" oder die Modulfunktion "List.head". Sie können auf den Tail einer Liste zugreifen, indem Sie die Tail-Eigenschaft oder die List.tail-Funktion verwenden. Verwenden Sie die List.nth-Funktion , um ein Element nach Index zu suchen. List.nth durchläuft die Liste. Daher ist es O(n). Wenn Ihr Code häufig verwendet List.nth wird, sollten Sie erwägen, anstelle einer Liste ein Array zu verwenden. Der Elementzugriff in Arrays ist O(1).

Boolesche Vorgänge in Listen

Die Funktion List.isEmpty bestimmt, ob eine Liste Elemente enthält.

Die Funktion List.exists wendet einen booleschen Test auf Elemente einer Liste an und gibt zurück true , wenn ein Element den Test erfüllt. List.exists2 ist ähnlich, funktioniert aber auf aufeinander folgenden Paaren von Elementen in zwei Listen.

Der folgende Code veranschaulicht die Verwendung von List.exists.

// Use List.exists to determine whether there is an element of a list satisfies a given Boolean expression.
// containsNumber returns true if any of the elements of the supplied list match
// the supplied number.
let containsNumber number list = List.exists (fun elem -> elem = number) list
let list0to3 = [0 .. 3]
printfn "For list %A, contains zero is %b" list0to3 (containsNumber 0 list0to3)

Die Ausgabe lautet wie folgt:

For list [0; 1; 2; 3], contains zero is true

Im folgenden Beispiel wird die Verwendung von List.exists2veranschaulicht.

// Use List.exists2 to compare elements in two lists.
// isEqualElement returns true if any elements at the same position in two supplied
// lists match.
let isEqualElement list1 list2 = List.exists2 (fun elem1 elem2 -> elem1 = elem2) list1 list2
let list1to5 = [ 1 .. 5 ]
let list5to1 = [ 5 .. -1 .. 1 ]
if (isEqualElement list1to5 list5to1) then
    printfn "Lists %A and %A have at least one equal element at the same position." list1to5 list5to1
else
    printfn "Lists %A and %A do not have an equal element at the same position." list1to5 list5to1

Die Ausgabe lautet wie folgt:

Lists [1; 2; 3; 4; 5] and [5; 4; 3; 2; 1] have at least one equal element at the same position.

Sie können List.forall verwenden, wenn Sie testen möchten, ob alle Elemente einer Liste eine Bedingung erfüllen.

let isAllZeroes list = List.forall (fun elem -> elem = 0.0) list
printfn "%b" (isAllZeroes [0.0; 0.0])
printfn "%b" (isAllZeroes [0.0; 1.0])

Die Ausgabe lautet wie folgt:

true
false

Ebenso bestimmt List.forall2 , ob alle Elemente in den entsprechenden Positionen in zwei Listen einen booleschen Ausdruck erfüllen, der jedes Elementpaar umfasst.

let listEqual list1 list2 = List.forall2 (fun elem1 elem2 -> elem1 = elem2) list1 list2
printfn "%b" (listEqual [0; 1; 2] [0; 1; 2])
printfn "%b" (listEqual [0; 0; 0] [0; 1; 0])

Die Ausgabe lautet wie folgt:

true
false

Sortiervorgänge in Listen

Die Listen "List.sort", "List.sortBy" und "List.sortWith" werden sortiert. Die Sortierfunktion bestimmt, welche dieser drei Funktionen verwendet werden sollen. List.sort verwendet standardmäßigen generischen Vergleich. Allgemeiner Vergleich verwendet globale Operatoren basierend auf der generischen Vergleichsfunktion zum Vergleichen von Werten. Es funktioniert effizient mit einer Vielzahl von Elementtypen, z. B. einfachen numerischen Typen, Tupeln, Datensätzen, diskriminierten Vereinigungen, Listen, Arrays und jedem Typ, der implementiert System.IComparablewird. Für Typen, die implementiert werden System.IComparable, verwendet der generische Vergleich die System.IComparable.CompareTo() Funktion. Der generische Vergleich funktioniert auch mit Zeichenfolgen, verwendet jedoch eine kulturunabhängige Sortierreihenfolge. Allgemeiner Vergleich sollte nicht für nicht unterstützte Typen verwendet werden, z. B. Funktionstypen. Außerdem ist die Leistung des standardmäßigen generischen Vergleichs für kleine strukturierte Typen am besten geeignet; für größere strukturierte Typen, die häufig verglichen und sortiert werden müssen, erwägen Sie die Implementierung System.IComparable und Bereitstellung einer effizienten Implementierung der System.IComparable.CompareTo() Methode.

List.sortBy verwendet eine Funktion, die einen Wert zurückgibt, der als Sortierkriterium verwendet wird, und List.sortWith verwendet eine Vergleichsfunktion als Argument. Diese beiden letztgenannten Funktionen sind nützlich, wenn Sie mit Typen arbeiten, die keinen Vergleich unterstützen oder wenn der Vergleich komplexere Vergleichsemantik erfordert, wie bei kulturfähigen Zeichenfolgen.

Im folgenden Beispiel wird die Verwendung von List.sortveranschaulicht.

let sortedList1 = List.sort [1; 4; 8; -2; 5]
printfn "%A" sortedList1

Die Ausgabe lautet wie folgt:

[-2; 1; 4; 5; 8]

Im folgenden Beispiel wird die Verwendung von List.sortByveranschaulicht.

let sortedList2 = List.sortBy (fun elem -> abs elem) [1; 4; 8; -2; 5]
printfn "%A" sortedList2

Die Ausgabe lautet wie folgt:

[1; -2; 4; 5; 8]

Das nächste Beispiel veranschaulicht die Verwendung von List.sortWith. In diesem Beispiel wird die benutzerdefinierte Vergleichsfunktion compareWidgets verwendet, um zuerst ein Feld eines benutzerdefinierten Typs zu vergleichen, und dann eine andere, wenn die Werte des ersten Felds gleich sind.

type Widget = { ID: int; Rev: int }

let compareWidgets widget1 widget2 =
   if widget1.ID < widget2.ID then -1 else
   if widget1.ID > widget2.ID then 1 else
   if widget1.Rev < widget2.Rev then -1 else
   if widget1.Rev > widget2.Rev then 1 else
   0

let listToCompare = [
    { ID = 92; Rev = 1 }
    { ID = 110; Rev = 1 }
    { ID = 100; Rev = 5 }
    { ID = 100; Rev = 2 }
    { ID = 92; Rev = 1 }
    ]

let sortedWidgetList = List.sortWith compareWidgets listToCompare
printfn "%A" sortedWidgetList

Die Ausgabe lautet wie folgt:

[{ID = 92;
Rev = 1;}; {ID = 92;
Rev = 1;}; {ID = 100;
Rev = 2;}; {ID = 100;
Rev = 5;}; {ID = 110;
Rev = 1;}]

Suchvorgänge in Listen

Zahlreiche Suchvorgänge werden für Listen unterstützt. Mit dem einfachsten " List.find" können Sie das erste Element finden, das einer bestimmten Bedingung entspricht.

Im folgenden Codebeispiel wird die Verwendung der List.find ersten Zahl veranschaulicht, die in einer Liste durch 5 divisierbar ist.

let isDivisibleBy number elem = elem % number = 0
let result = List.find (isDivisibleBy 5) [ 1 .. 100 ]
printfn "%d " result

Das Ergebnis ist 5.

Wenn die Elemente zuerst transformiert werden müssen, rufen Sie List.pick auf, die eine Funktion verwendet, die eine Option zurückgibt, und sucht nach dem ersten Optionswert, der lautet Some(x). Statt das Element zurückzugeben, List.pick wird das Ergebnis xzurückgegeben. Wenn kein übereinstimmende Element gefunden wird, List.pick wird ausgelöst System.Collections.Generic.KeyNotFoundException. Der folgende Code zeigt die Verwendung von List.pick.

let valuesList = [ ("a", 1); ("b", 2); ("c", 3) ]

let resultPick = List.pick (fun elem ->
                    match elem with
                    | (value, 2) -> Some value
                    | _ -> None) valuesList
printfn "%A" resultPick

Die Ausgabe lautet wie folgt:

"b"

Eine andere Gruppe von Suchvorgängen, List.tryFind und verwandte Funktionen, geben einen Optionswert zurück. Die List.tryFind Funktion gibt das erste Element einer Liste zurück, das eine Bedingung erfüllt, wenn ein solches Element vorhanden ist, aber der Optionswert None , wenn nicht. The variations List.tryFindIndex returns the index of the element, if one is found, rather than the element itself. Diese Funktionen werden im folgenden Code veranschaulicht.

let list1d = [1; 3; 7; 9; 11; 13; 15; 19; 22; 29; 36]
let isEven x = x % 2 = 0
match List.tryFind isEven list1d with
| Some value -> printfn "The first even value is %d." value
| None -> printfn "There is no even value in the list."

match List.tryFindIndex isEven list1d with
| Some value -> printfn "The first even value is at position %d." value
| None -> printfn "There is no even value in the list."

Die Ausgabe lautet wie folgt:

The first even value is 22.
The first even value is at position 8.

Arithmetische Vorgänge in Listen

Allgemeine arithmetische Vorgänge wie Summe und Mittelwert sind in das Listenmodul integriert. Um mit List.sum zu arbeiten, muss der Listenelementtyp den + Operator unterstützen und einen Nullwert aufweisen. Alle integrierten arithmetischen Typen erfüllen diese Bedingungen. Um mit List.average zu arbeiten, muss der Elementtyp die Division ohne Rest unterstützen, was integrale Typen ausschließt, aber Gleitkommatypen zulässt. Die Funktionen List.sumBy und List.averageBy verwenden eine Funktion als Parameter, und die Ergebnisse dieser Funktion werden verwendet, um die Werte für die Summe oder den Mittelwert zu berechnen.

Der folgende Code veranschaulicht die Verwendung von List.sum, List.sumByund List.average.

// Compute the sum of the first 10 integers by using List.sum.
let sum1 = List.sum [1 .. 10]

// Compute the sum of the squares of the elements of a list by using List.sumBy.
let sum2 = List.sumBy (fun elem -> elem*elem) [1 .. 10]

// Compute the average of the elements of a list by using List.average.
let avg1 = List.average [0.0; 1.0; 1.0; 2.0]

printfn "%f" avg1

Die Ausgabe lautet 1.000000.

Der folgende Code zeigt die Verwendung von List.averageBy.

let avg2 = List.averageBy (fun elem -> float elem) [1 .. 10]
printfn "%f" avg2

Die Ausgabe lautet 5.5.

Listen und Tupel

Listen, die Tupel enthalten, können von ZIP- und Entpackfunktionen bearbeitet werden. Diese Funktionen kombinieren zwei Listen mit einzelnen Werten in einer Liste von Tupeln oder trennen eine Liste von Tupeln in zwei Listen mit einzelnen Werten. Die einfachste List.zip-Funktion verwendet zwei Listen einzelner Elemente und erzeugt eine einzelne Liste von Tupelpaaren. Eine andere Version, List.zip3, akzeptiert drei Listen einzelner Elemente und erzeugt eine einzelne Liste von Tupeln mit drei Elementen. Das folgende Codebeispiel veranschaulicht die Verwendung von List.zip.

let list1 = [ 1; 2; 3 ]
let list2 = [ -1; -2; -3 ]
let listZip = List.zip list1 list2
printfn "%A" listZip

Die Ausgabe lautet wie folgt:

[(1, -1); (2, -2); (3; -3)]

Das folgende Codebeispiel veranschaulicht die Verwendung von List.zip3.

let list3 = [ 0; 0; 0]
let listZip3 = List.zip3 list1 list2 list3
printfn "%A" listZip3

Die Ausgabe lautet wie folgt:

[(1, -1, 0); (2, -2, 0); (3, -3, 0)]

Die entsprechenden Entzippenversionen , List.unzip3 und List.unzip3, take lists of tuple and return lists in a tuple, where the first list contains all the elements that were first in each tuple, and the second list contains the second element of each tuple, and so on.

Im folgenden Codebeispiel wird die Verwendung von List.unzip veranschaulicht.

let lists = List.unzip [(1,2); (3,4)]
printfn "%A" lists
printfn "%A %A" (fst lists) (snd lists)

Die Ausgabe lautet wie folgt:

([1; 3], [2; 4])
[1; 3] [2; 4]

Im folgenden Codebeispiel wird die Verwendung von List.unzip3 veranschaulicht.

let listsUnzip3 = List.unzip3 [(1,2,3); (4,5,6)]
printfn "%A" listsUnzip3

Die Ausgabe lautet wie folgt:

([1; 4], [2; 5], [3; 6])

Arbeiten mit Listenelementen

F# unterstützt eine Vielzahl von Vorgängen für Listenelemente. Das einfachste ist List.iter, mit dem Sie eine Funktion für jedes Element einer Liste aufrufen können. Variationen umfassen List.iter2, die es Ihnen ermöglichen, einen Vorgang für Elemente von zwei Listen auszuführen, List.iteri, das mit List.iter der Ausnahme ist, dass der Index jedes Elements als Argument an die Funktion übergeben wird, die für jedes Element aufgerufen wird, und List.iteri2, die eine Kombination der Funktionalität von List.iter2 und List.iteri. Im folgenden Codebeispiel werden diese Funktionen veranschaulicht.

let list1 = [1; 2; 3]
let list2 = [4; 5; 6]
List.iter (fun x -> printfn "List.iter: element is %d" x) list1
List.iteri(fun i x -> printfn "List.iteri: element %d is %d" i x) list1
List.iter2 (fun x y -> printfn "List.iter2: elements are %d %d" x y) list1 list2
List.iteri2 (fun i x y ->
                printfn "List.iteri2: element %d of list1 is %d element %d of list2 is %d"
                  i x i y)
            list1 list2

Die Ausgabe lautet wie folgt:

List.iter: element is 1
List.iter: element is 2
List.iter: element is 3
List.iteri: element 0 is 1
List.iteri: element 1 is 2
List.iteri: element 2 is 3
List.iter2: elements are 1 4
List.iter2: elements are 2 5
List.iter2: elements are 3 6
List.iteri2: element 0 of list1 is 1; element 0 of list2 is 4
List.iteri2: element 1 of list1 is 2; element 1 of list2 is 5
List.iteri2: element 2 of list1 is 3; element 2 of list2 is 6

Eine weitere häufig verwendete Funktion, die Listenelemente transformiert, ist List.map, mit der Sie eine Funktion auf jedes Element einer Liste anwenden und alle Ergebnisse in eine neue Liste einfügen können. List.map2 und List.map3 sind Variationen, die mehrere Listen enthalten. Sie können auch List.mapi und List.mapi2 verwenden, wenn zusätzlich zum Element die Funktion den Index der einzelnen Elemente übergeben werden muss. Der einzige Unterschied zwischen List.mapi2 und List.mapi ist, dass es List.mapi2 mit zwei Listen funktioniert. Das folgende Beispiel veranschaulicht List.map.

let list1 = [1; 2; 3]
let newList = List.map (fun x -> x + 1) list1
printfn "%A" newList

Die Ausgabe lautet wie folgt:

[2; 3; 4]

Im folgenden Beispiel wird die Verwendung von List.map2 veranschaulicht.

let list1 = [1; 2; 3]
let list2 = [4; 5; 6]
let sumList = List.map2 (fun x y -> x + y) list1 list2
printfn "%A" sumList

Die Ausgabe lautet wie folgt:

[5; 7; 9]

Im folgenden Beispiel wird die Verwendung von List.map3 veranschaulicht.

let newList2 = List.map3 (fun x y z -> x + y + z) list1 list2 [2; 3; 4]
printfn "%A" newList2

Die Ausgabe lautet wie folgt:

[7; 10; 13]

Im folgenden Beispiel wird die Verwendung von List.mapi veranschaulicht.

let newListAddIndex = List.mapi (fun i x -> x + i) list1
printfn "%A" newListAddIndex

Die Ausgabe lautet wie folgt:

[1; 3; 5]

Im folgenden Beispiel wird die Verwendung von List.mapi2 veranschaulicht.

let listAddTimesIndex = List.mapi2 (fun i x y -> (x + y) * i) list1 list2
printfn "%A" listAddTimesIndex

Die Ausgabe lautet wie folgt:

[0; 7; 18]

List.collect ist gleich List.map, mit der Ausnahme, dass jedes Element eine Liste erzeugt und alle diese Listen in eine endgültige Liste verkettet werden. Im folgenden Code generiert jedes Element der Liste drei Zahlen. Diese werden alle in einer Liste gesammelt.

let collectList = List.collect (fun x -> [for i in 1..3 -> x * i]) list1
printfn "%A" collectList

Die Ausgabe lautet wie folgt:

[1; 2; 3; 2; 4; 6; 3; 6; 9]

Sie können auch List.filter verwenden, die eine boolesche Bedingung akzeptiert und eine neue Liste erzeugt, die nur aus Elementen besteht, die die angegebene Bedingung erfüllen.

let evenOnlyList = List.filter (fun x -> x % 2 = 0) [1; 2; 3; 4; 5; 6]

Die resultierende Liste ist [2; 4; 6].

Eine Kombination aus Karten und Filter ermöglicht es Ihnen , Elemente gleichzeitig zu transformieren und auszuwählen. List.choose wendet eine Funktion an, die eine Option auf jedes Element einer Liste zurückgibt, und gibt eine neue Liste der Ergebnisse für Elemente zurück, wenn die Funktion den Optionswert Somezurückgibt.

Der folgende Code veranschaulicht die Verwendung von List.choose großgeschriebenen Wörtern aus einer Liste von Wörtern.

let listWords = [ "and"; "Rome"; "Bob"; "apple"; "zebra" ]
let isCapitalized (string1:string) = System.Char.IsUpper string1[0]
let results = List.choose (fun elem ->
    match elem with
    | elem when isCapitalized elem -> Some(elem + "'s")
    | _ -> None) listWords
printfn "%A" results

Die Ausgabe lautet wie folgt:

["Rome's"; "Bob's"]

Arbeiten mit mehreren Listen

Listen können miteinander verknüpft werden. Verwenden Sie "List.append", um zwei Listen mit einem Listen zu verbinden. Verwenden Sie "List.concat", um mehr als zwei Listen zu verbinden.

let list1to10 = List.append [1; 2; 3] [4; 5; 6; 7; 8; 9; 10]
let listResult = List.concat [ [1; 2; 3]; [4; 5; 6]; [7; 8; 9] ]
List.iter (fun elem -> printf "%d " elem) list1to10
printfn ""
List.iter (fun elem -> printf "%d " elem) listResult

Falt- und Scanvorgänge

Einige Listenvorgänge umfassen Abhängigkeiten zwischen allen Listenelementen. Die Falt- und Scanvorgänge sind ähnlich List.iter und List.map enthalten, dass Sie eine Funktion für jedes Element aufrufen, aber diese Vorgänge stellen einen zusätzlichen Parameter bereit, der als Akkumulator bezeichnet wird, der Informationen über die Berechnung enthält.

Wird List.fold verwendet, um eine Berechnung für eine Liste auszuführen.

Im folgenden Codebeispiel wird die Verwendung von List.fold zum Ausführen verschiedener Vorgänge veranschaulicht.

Die Liste wird durchlaufen; Der Akkumulator acc ist ein Wert, der übergeben wird, wenn die Berechnung fortgesetzt wird. Das erste Argument verwendet den Akkumulator und das Listenelement und gibt das Zwischenergebnis der Berechnung für dieses Listenelement zurück. Das zweite Argument ist der Anfangswert des Akkumulators.

let sumList list = List.fold (fun acc elem -> acc + elem) 0 list
printfn "Sum of the elements of list %A is %d." [ 1 .. 3 ] (sumList [ 1 .. 3 ])

// The following example computes the average of a list.
let averageList list = (List.fold (fun acc elem -> acc + float elem) 0.0 list / float list.Length)

// The following example computes the standard deviation of a list.
// The standard deviation is computed by taking the square root of the
// sum of the variances, which are the differences between each value
// and the average.
let stdDevList list =
    let avg = averageList list
    sqrt (List.fold (fun acc elem -> acc + (float elem - avg) ** 2.0 ) 0.0 list / float list.Length)

let testList listTest =
    printfn "List %A average: %f stddev: %f" listTest (averageList listTest) (stdDevList listTest)

testList [1; 1; 1]
testList [1; 2; 1]
testList [1; 2; 3]

// List.fold is the same as to List.iter when the accumulator is not used.
let printList list = List.fold (fun acc elem -> printfn "%A" elem) () list
printList [0.0; 1.0; 2.5; 5.1 ]

// The following example uses List.fold to reverse a list.
// The accumulator starts out as the empty list, and the function uses the cons operator
// to add each successive element to the head of the accumulator list, resulting in a
// reversed form of the list.
let reverseList list = List.fold (fun acc elem -> elem::acc) [] list
printfn "%A" (reverseList [1 .. 10])

Die Versionen dieser Funktionen, die über eine Ziffer im Funktionsnamen verfügen, werden in mehreren Listen ausgeführt. Beispielsweise führt List.fold2 Berechnungen für zwei Listen durch.

Im folgenden Beispiel wird die Verwendung von List.fold2veranschaulicht.

// Use List.fold2 to perform computations over two lists (of equal size) at the same time.
// Example: Sum the greater element at each list position.
let sumGreatest list1 list2 = List.fold2 (fun acc elem1 elem2 ->
                                              acc + max elem1 elem2) 0 list1 list2

let sum = sumGreatest [1; 2; 3] [3; 2; 1]
printfn "The sum of the greater of each pair of elements in the two lists is %d." sum

List.fold und List.scan unterscheiden sich darin, dass List.fold der endgültige Wert des zusätzlichen Parameters zurückgegeben wird, aber List.scan die Liste der Zwischenwerte (zusammen mit dem Endwert) des zusätzlichen Parameters zurückgibt.

Jede dieser Funktionen enthält eine umgekehrte Variation, z. B. List.foldBack, die sich in der Reihenfolge unterscheidet, in der die Liste durchlaufen wird, und die Reihenfolge der Argumente. List.fold Außerdem haben Sie List.foldBack Variationen, List.fold2 und List.foldBack2, die zwei Listen gleicher Länge enthalten. Die Funktion, die für jedes Element ausgeführt wird, kann entsprechende Elemente beider Listen verwenden, um eine Aktion auszuführen. Die Elementtypen der beiden Listen können unterschiedlich sein, wie im folgenden Beispiel, in dem eine Liste Transaktionsbeträge für ein Bankkonto enthält, und die andere Liste enthält den Typ der Transaktion: Einzahlung oder Auszahlung.

// Discriminated union type that encodes the transaction type.
type Transaction =
    | Deposit
    | Withdrawal

let transactionTypes = [Deposit; Deposit; Withdrawal]
let transactionAmounts = [100.00; 1000.00; 95.00 ]
let initialBalance = 200.00

// Use fold2 to perform a calculation on the list to update the account balance.
let endingBalance = List.fold2 (fun acc elem1 elem2 ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2)
                                initialBalance
                                transactionTypes
                                transactionAmounts
printfn "%f" endingBalance

Bei einer Berechnung wie summen und List.foldBack haben die gleiche Auswirkung, List.fold da das Ergebnis nicht von der Reihenfolge der Durchquerung abhängt. Im folgenden Beispiel wird verwendet, List.foldBack um die Elemente in einer Liste hinzuzufügen.

let sumListBack list = List.foldBack (fun elem acc -> acc + elem) list 0
printfn "%d" (sumListBack [1; 2; 3])

// For a calculation in which the order of traversal is important, fold and foldBack have different
// results. For example, replacing fold with foldBack in the listReverse function
// produces a function that copies the list, rather than reversing it.
let copyList list = List.foldBack (fun elem acc -> elem::acc) list []
printfn "%A" (copyList [1 .. 10])

Im folgenden Beispiel wird das Bankkontobeispiel zurückgegeben. Dieses Mal wird ein neuer Transaktionstyp hinzugefügt: eine Zinsberechnung. Der Endsaldo hängt jetzt von der Reihenfolge der Transaktionen ab.

type Transaction2 =
    | Deposit
    | Withdrawal
    | Interest

let transactionTypes2 = [Deposit; Deposit; Withdrawal; Interest]
let transactionAmounts2 = [100.00; 1000.00; 95.00; 0.05 / 12.0 ]
let initialBalance2 = 200.00

// Because fold2 processes the lists by starting at the head element,
// the interest is calculated last, on the balance of 1205.00.
let endingBalance2 = List.fold2 (fun acc elem1 elem2 ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2
                                | Interest -> acc * (1.0 + elem2))
                                initialBalance2
                                transactionTypes2
                                transactionAmounts2
printfn "%f" endingBalance2


// Because foldBack2 processes the lists by starting at end of the list,
// the interest is calculated first, on the balance of only 200.00.
let endingBalance3 = List.foldBack2 (fun elem1 elem2 acc ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2
                                | Interest -> acc * (1.0 + elem2))
                                transactionTypes2
                                transactionAmounts2
                                initialBalance2
printfn "%f" endingBalance3

Die Funktion List.reduce ist etwas ähnlich List.fold , und List.scan, außer dass anstelle eines separaten Akkumulators eine Funktion verwendet wird, List.reduce die zwei Argumente des Elementtyps anstelle von nur einem verwendet, und eines dieser Argumente fungiert als Akkumulator, d. h., es speichert das Zwischenergebnis der Berechnung. List.reduce beginnt mit der Verwendung der ersten beiden Listenelemente und verwendet dann das Ergebnis des Vorgangs zusammen mit dem nächsten Element. Da es keinen separaten Akkumulator gibt, der über einen eigenen Typ verfügt, kann anstelle von List.fold nur verwendet werden, List.reduce wenn der Akkumulator und der Elementtyp denselben Typ haben. Der folgende Code veranschaulicht die Verwendung von List.reduce. List.reduce löst eine Ausnahme aus, wenn die angegebene Liste keine Elemente enthält.

Im folgenden Code erhält der erste Aufruf des Lambda-Ausdrucks die Argumente 2 und 4 und gibt 6 zurück, und der nächste Aufruf erhält die Argumente 6 und 10, sodass das Ergebnis 16 ist.

let sumAList list =
    try
        List.reduce (fun acc elem -> acc + elem) list
    with
       | :? System.ArgumentException as exc -> 0

let resultSum = sumAList [2; 4; 10]
printfn "%d " resultSum

Konvertieren zwischen Listen und anderen Auflistungstypen

Das List Modul bietet Funktionen zum Konvertieren in und aus Sequenzen und Arrays. Zum Konvertieren in oder aus einer Sequenz verwenden Sie List.toSeq oder List.ofSeq. Verwenden Sie "List.toArray " oder "List.ofArray", um in ein Oder aus einem Array zu konvertieren.

Zusätzliche Vorgänge

Informationen zu zusätzlichen Vorgängen in Listen finden Sie im Bibliotheksreferenzthema Listenmodul.

Siehe auch