Lijsten
Een lijst in F# is een geordende, onveranderbare reeks elementen van hetzelfde type. Als u basisbewerkingen wilt uitvoeren op lijsten, gebruikt u de functies in de lijstmodule.
Lijsten maken en initialiseren
U kunt een lijst definiëren door de elementen expliciet weer te geven, gescheiden door puntkomma's en tussen vierkante haken, zoals wordt weergegeven in de volgende regel code.
let list123 = [ 1; 2; 3 ]
U kunt ook regeleinden tussen elementen plaatsen. In dat geval zijn de puntkomma's optioneel. De laatste syntaxis kan resulteren in meer leesbare code wanneer de expressies voor het initialiseren van elementen langer zijn of wanneer u een opmerking voor elk element wilt opnemen.
let list123 = [ 1; 2; 3 ]
Normaal gesproken moeten alle lijstelementen hetzelfde type zijn. Een uitzondering is dat een lijst waarin de elementen zijn opgegeven als basistype, elementen kan bevatten die afgeleide typen zijn. Het volgende is dus aanvaardbaar, omdat beide Button
en CheckBox
afgeleid zijn van Control
.
let myControlList: Control list = [ new Button(); new CheckBox() ]
U kunt ook lijstelementen definiëren met behulp van een bereik dat wordt aangegeven door gehele getallen, gescheiden door de bereikoperator (..
), zoals wordt weergegeven in de volgende code.
let list1 = [ 1..10 ]
Er wordt een lege lijst opgegeven door een paar vierkante haken met ertussen niets.
// An empty list.
let listEmpty = []
U kunt ook een reeksexpressie gebruiken om een lijst te maken. Zie Reeksexpressies voor meer informatie. Met de volgende code maakt u bijvoorbeeld een lijst met kwadraten van gehele getallen van 1 tot 10.
let listOfSquares = [ for i in 1..10 -> i * i ]
Operators voor het werken met lijsten
U kunt elementen aan een lijst koppelen met behulp van de ::
operator (nadelen). Als list1
dat het is [2; 3; 4]
, wordt de volgende code gemaakt list2
als [100; 2; 3; 4]
.
let list2 = 100 :: list1
U kunt lijsten met compatibele typen samenvoegen met behulp van de @
operator, zoals in de volgende code. Als list1
dat het is [2; 3; 4]
en list2
is [100; 2; 3; 4]
, wordt deze code gemaakt list3
als [2; 3; 4; 100; 2; 3; 4]
.
let list3 = list1 @ list2
Functies voor het uitvoeren van bewerkingen op lijsten zijn beschikbaar in de lijstmodule.
Omdat lijsten in F# onveranderbaar zijn, genereren alle wijzigingsbewerkingen nieuwe lijsten in plaats van bestaande lijsten te wijzigen.
Lijsten in F# worden geïmplementeerd als ingly gekoppelde lijsten, wat betekent dat bewerkingen die alleen toegang hebben tot het hoofd van de lijst O(1) zijn en dat de toegang tot elementen O(n) is.
Eigenschappen
Het lijsttype ondersteunt de volgende eigenschappen:
Eigenschap | Type | Description |
---|---|---|
Hoofd | 'T |
Het eerste element. |
Lege | 'T list |
Een statische eigenschap die een lege lijst met het juiste type retourneert. |
IsEmpty | bool |
true als de lijst geen elementen bevat. |
Artikel | 'T |
Het element op de opgegeven index (op basis van nul). |
Lengte | int |
Het aantal elementen. |
Staart | 'T list |
De lijst zonder het eerste element. |
Hieronder volgen enkele voorbeelden van het gebruik van deze eigenschappen.
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))
Lijsten gebruiken
Door te programmeren met lijsten kunt u complexe bewerkingen uitvoeren met een kleine hoeveelheid code. In deze sectie worden algemene bewerkingen beschreven voor lijsten die belangrijk zijn voor functionele programmering.
Recursie met lijsten
Lijsten zijn uniek geschikt voor recursieve programmeertechnieken. Overweeg een bewerking die moet worden uitgevoerd op elk element van een lijst. U kunt dit recursief doen door op het hoofd van de lijst te werken en vervolgens de staart van de lijst door te geven. Dit is een kleinere lijst die bestaat uit de oorspronkelijke lijst zonder het eerste element, terug naar het volgende niveau van recursie.
Als u een dergelijke recursieve functie wilt schrijven, gebruikt u de operator cons (::
) in patroonkoppeling, waarmee u het hoofd van een lijst van de staart kunt scheiden.
In het volgende codevoorbeeld ziet u hoe u patroonkoppeling gebruikt om een recursieve functie te implementeren waarmee bewerkingen in een lijst worden uitgevoerd.
let rec sum list =
match list with
| head :: tail -> head + sum tail
| [] -> 0
De vorige code werkt goed voor kleine lijsten, maar voor grotere lijsten kan de stack overlopen. De volgende code verbetert deze code met behulp van een accumulatorargument, een standaardtechniek voor het werken met recursieve functies. Het gebruik van het accumulatorargument maakt de functiestaart recursief, waardoor stackruimte wordt bespaard.
let sum list =
let rec loop list acc =
match list with
| head :: tail -> loop tail (acc + head)
| [] -> acc
loop list 0
De functie RemoveAllMultiples
is een recursieve functie die twee lijsten gebruikt. De eerste lijst bevat de getallen waarvan de veelvouden worden verwijderd en de tweede lijst is de lijst waaruit de getallen moeten worden verwijderd. In de code in het volgende voorbeeld wordt deze recursieve functie gebruikt om alle niet-priemgetallen uit een lijst te elimineren, waarbij een lijst met priemgetallen wordt achtergelaten als resultaat.
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)
De uitvoer is als volgt:
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]
Modulefuncties
De module List biedt functies die toegang hebben tot de elementen van een lijst. Het hoofdelement is de snelste en eenvoudigste toegang. Gebruik de eigenschap Head of de modulefunctie List.head. U kunt de staart van een lijst openen met behulp van de eigenschap Tail of de functie List.tail . Als u een element per index wilt zoeken, gebruikt u de functie List.nth . List.nth
gaat door de lijst. Daarom is het O(n). Als uw code vaak wordt gebruikt List.nth
, kunt u overwegen om een matrix te gebruiken in plaats van een lijst. Toegang tot elementen in matrices is O(1).
Booleaanse bewerkingen in lijsten
De functie List.isEmpty bepaalt of een lijst elementen bevat.
De functie List.exists past een Booleaanse test toe op elementen van een lijst en retourneert true
of een element voldoet aan de test. List.exists2 is vergelijkbaar, maar werkt op opeenvolgende paren elementen in twee lijsten.
De volgende code demonstreert het gebruik van 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)
De uitvoer is als volgt:
For list [0; 1; 2; 3], contains zero is true
In het volgende voorbeeld ziet u het gebruik van List.exists2
.
// 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
De uitvoer is als volgt:
Lists [1; 2; 3; 4; 5] and [5; 4; 3; 2; 1] have at least one equal element at the same position.
U kunt List.forall gebruiken als u wilt testen of alle elementen van een lijst aan een voorwaarde voldoen.
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])
De uitvoer is als volgt:
true
false
Op dezelfde manier bepaalt List.forall2 of alle elementen in de bijbehorende posities in twee lijsten voldoen aan een Boole-expressie die elk paar elementen omvat.
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])
De uitvoer is als volgt:
true
false
Sorteerbewerkingen op lijsten
De functies List.sort, List.sortBy en List.sortWith sorteren lijsten. De sorteerfunctie bepaalt welke van deze drie functies moeten worden gebruikt. List.sort
maakt gebruik van standaard algemene vergelijking. Algemene vergelijking maakt gebruik van globale operators op basis van de algemene vergelijkingsfunctie om waarden te vergelijken. Het werkt efficiënt met een breed scala aan elementtypen, zoals eenvoudige numerieke typen, tuples, records, gediscrimineerde samenvoegingen, lijsten, matrices en elk type dat wordt geïmplementeerd System.IComparable
. Voor typen die worden geïmplementeerd System.IComparable
, maakt algemene vergelijking gebruik van de System.IComparable.CompareTo()
functie. Algemene vergelijking werkt ook met tekenreeksen, maar maakt gebruik van een cultuuronafhankelijke sorteervolgorde. Algemene vergelijking mag niet worden gebruikt voor niet-ondersteunde typen, zoals functietypen. Bovendien is de prestaties van de standaard algemene vergelijking het beste voor kleine gestructureerde typen; voor grotere gestructureerde typen die regelmatig moeten worden vergeleken en gesorteerd, kunt u overwegen om een efficiënte implementatie van de System.IComparable.CompareTo()
methode te implementeren System.IComparable
en te bieden.
List.sortBy
gebruikt een functie die een waarde retourneert die wordt gebruikt als het sorteercriterium en List.sortWith
een vergelijkingsfunctie als argument gebruikt. Deze laatste twee functies zijn handig wanneer u werkt met typen die geen ondersteuning bieden voor vergelijking, of wanneer de vergelijking complexere vergelijkingsemantiek vereist, zoals in het geval van cultuurbewuste tekenreeksen.
In het volgende voorbeeld ziet u het gebruik van List.sort
.
let sortedList1 = List.sort [1; 4; 8; -2; 5]
printfn "%A" sortedList1
De uitvoer is als volgt:
[-2; 1; 4; 5; 8]
In het volgende voorbeeld ziet u het gebruik van List.sortBy
.
let sortedList2 = List.sortBy (fun elem -> abs elem) [1; 4; 8; -2; 5]
printfn "%A" sortedList2
De uitvoer is als volgt:
[1; -2; 4; 5; 8]
In het volgende voorbeeld ziet u het gebruik van List.sortWith
. In dit voorbeeld wordt de aangepaste vergelijkingsfunctie compareWidgets
gebruikt om eerst één veld van een aangepast type te vergelijken en vervolgens een andere wanneer de waarden van het eerste veld gelijk zijn.
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
De uitvoer is als volgt:
[{ID = 92;
Rev = 1;}; {ID = 92;
Rev = 1;}; {ID = 100;
Rev = 2;}; {ID = 100;
Rev = 5;}; {ID = 110;
Rev = 1;}]
Zoekbewerkingen op lijsten
Er worden talloze zoekbewerkingen ondersteund voor lijsten. Met list.find kunt u het eerste element vinden dat overeenkomt met een bepaalde voorwaarde.
In het volgende codevoorbeeld ziet u hoe u het List.find
eerste getal kunt vinden dat deelbaar is door 5 in een lijst.
let isDivisibleBy number elem = elem % number = 0
let result = List.find (isDivisibleBy 5) [ 1 .. 100 ]
printfn "%d " result
Het resultaat is 5.
Als de elementen eerst moeten worden getransformeerd, roept u List.pick aan, waarbij een functie wordt gebruikt die een optie retourneert en zoekt naar de eerste optiewaarde die is Some(x)
. In plaats van het element te retourneren, List.pick
wordt het resultaat geretourneerd x
. Als er geen overeenkomend element wordt gevonden, List.pick
gooit System.Collections.Generic.KeyNotFoundException
u . De volgende code toont het gebruik van 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
De uitvoer is als volgt:
"b"
Een andere groep zoekbewerkingen, List.tryFind en gerelateerde functies, retourneert een optiewaarde. De List.tryFind
functie retourneert het eerste element van een lijst die voldoet aan een voorwaarde als een dergelijk element bestaat, maar de optiewaarde None
als dat niet het beste is. De variatie List.tryFindIndex retourneert de index van het element, als deze wordt gevonden, in plaats van het element zelf. Deze functies worden geïllustreerd in de volgende code.
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."
De uitvoer is als volgt:
The first even value is 22.
The first even value is at position 8.
Rekenkundige bewerkingen op lijsten
Algemene rekenkundige bewerkingen, zoals som en gemiddelde, zijn ingebouwd in de lijstmodule. Als u met List.sum wilt werken, moet het type lijstelement de +
operator ondersteunen en een nulwaarde hebben. Alle ingebouwde rekenkundige typen voldoen aan deze voorwaarden. Als u met List.average wilt werken, moet het elementtype delen ondersteunen zonder rest, waarbij integrale typen worden uitgesloten, maar waarmee drijvendekommatypen worden toegestaan. De functies List.sumBy en List.averageBy nemen een functie als parameter en de resultaten van deze functie worden gebruikt om de waarden voor de som of het gemiddelde te berekenen.
De volgende code demonstreert het gebruik van List.sum
, List.sumBy
en 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
De uitvoer is 1.000000
.
De volgende code toont het gebruik van List.averageBy
.
let avg2 = List.averageBy (fun elem -> float elem) [1 .. 10]
printfn "%f" avg2
De uitvoer is 5.5
.
Lijsten en tuples
Lijsten die tuples bevatten, kunnen worden bewerkt door zip- en uitpakfuncties. Deze functies combineren twee lijsten met enkele waarden in één lijst met tuples of scheiden één lijst met tuples in twee lijsten met enkele waarden. De eenvoudigste List.zip functie neemt twee lijsten met enkele elementen en produceert één lijst met tupleparen. Een andere versie, List.zip3, neemt drie lijsten met enkele elementen en produceert één lijst met tuples met drie elementen. In het volgende codevoorbeeld ziet u het gebruik van List.zip
.
let list1 = [ 1; 2; 3 ]
let list2 = [ -1; -2; -3 ]
let listZip = List.zip list1 list2
printfn "%A" listZip
De uitvoer is als volgt:
[(1, -1); (2, -2); (3; -3)]
In het volgende codevoorbeeld ziet u het gebruik van List.zip3
.
let list3 = [ 0; 0; 0]
let listZip3 = List.zip3 list1 list2 list3
printfn "%A" listZip3
De uitvoer is als volgt:
[(1, -1, 0); (2, -2, 0); (3, -3, 0)]
De bijbehorende unzip versies, List.unzip en List.unzip3, take lists of tuples and return lists in a tuple, where the first list contains all elements that were first in each tuple, and the second list contains the second element of each tuple, enzovoort.
In het volgende codevoorbeeld ziet u hoe List.unzip wordt gebruikt.
let lists = List.unzip [(1,2); (3,4)]
printfn "%A" lists
printfn "%A %A" (fst lists) (snd lists)
De uitvoer is als volgt:
([1; 3], [2; 4])
[1; 3] [2; 4]
In het volgende codevoorbeeld ziet u hoe List.unzip3 wordt gebruikt.
let listsUnzip3 = List.unzip3 [(1,2,3); (4,5,6)]
printfn "%A" listsUnzip3
De uitvoer is als volgt:
([1; 4], [2; 5], [3; 6])
Werken op lijstelementen
F# ondersteunt verschillende bewerkingen op lijstelementen. De eenvoudigste is List.iter, waarmee u een functie kunt aanroepen voor elk element van een lijst. Variaties zijn List.iter2, waarmee u een bewerking kunt uitvoeren op elementen van twee lijsten, List.iteri, die vergelijkbaar List.iter
is, behalve dat de index van elk element wordt doorgegeven als een argument voor de functie die voor elk element wordt aangeroepen, en List.iteri2, een combinatie van de functionaliteit van List.iter2
en List.iteri
. In het volgende codevoorbeeld ziet u deze functies.
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
De uitvoer is als volgt:
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
Een andere veelgebruikte functie waarmee lijstelementen worden getransformeerd, is List.map, waarmee u een functie kunt toepassen op elk element van een lijst en alle resultaten in een nieuwe lijst kunt plaatsen. List.map2 en List.map3 zijn variaties die meerdere lijsten aannemen. U kunt ook List.mapi en List.mapi2 gebruiken, als naast het element de functie moet worden doorgegeven aan de index van elk element. Het enige verschil tussen List.mapi2
en List.mapi
is dat List.mapi2
werkt met twee lijsten. In het volgende voorbeeld ziet u List.map.
let list1 = [1; 2; 3]
let newList = List.map (fun x -> x + 1) list1
printfn "%A" newList
De uitvoer is als volgt:
[2; 3; 4]
In het volgende voorbeeld ziet u het gebruik van List.map2
.
let list1 = [1; 2; 3]
let list2 = [4; 5; 6]
let sumList = List.map2 (fun x y -> x + y) list1 list2
printfn "%A" sumList
De uitvoer is als volgt:
[5; 7; 9]
In het volgende voorbeeld ziet u het gebruik van List.map3
.
let newList2 = List.map3 (fun x y z -> x + y + z) list1 list2 [2; 3; 4]
printfn "%A" newList2
De uitvoer is als volgt:
[7; 10; 13]
In het volgende voorbeeld ziet u het gebruik van List.mapi
.
let newListAddIndex = List.mapi (fun i x -> x + i) list1
printfn "%A" newListAddIndex
De uitvoer is als volgt:
[1; 3; 5]
In het volgende voorbeeld ziet u het gebruik van List.mapi2
.
let listAddTimesIndex = List.mapi2 (fun i x y -> (x + y) * i) list1 list2
printfn "%A" listAddTimesIndex
De uitvoer is als volgt:
[0; 7; 18]
List.collect lijkt op List.map
, behalve dat elk element een lijst produceert en al deze lijsten worden samengevoegd in een definitieve lijst. In de volgende code genereert elk element van de lijst drie getallen. Deze worden allemaal verzameld in één lijst.
let collectList = List.collect (fun x -> [for i in 1..3 -> x * i]) list1
printfn "%A" collectList
De uitvoer is als volgt:
[1; 2; 3; 2; 4; 6; 3; 6; 9]
U kunt ook List.filter gebruiken, waarbij een Booleaanse voorwaarde wordt gebruikt en een nieuwe lijst wordt gegenereerd die alleen bestaat uit elementen die voldoen aan de opgegeven voorwaarde.
let evenOnlyList = List.filter (fun x -> x % 2 = 0) [1; 2; 3; 4; 5; 6]
De resulterende lijst is [2; 4; 6]
.
Met een combinatie van kaart en filter kunt u met List.choose elementen tegelijk transformeren en selecteren. List.choose
past een functie toe die een optie retourneert voor elk element van een lijst en retourneert een nieuwe lijst met de resultaten voor elementen wanneer de functie de optiewaarde retourneert Some
.
In de volgende code wordt het gebruik gedemonstreerd van het selecteren van List.choose
woorden met hoofdletters uit een lijst met woorden.
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
De uitvoer is als volgt:
["Rome's"; "Bob's"]
Werken op meerdere lijsten
Lijsten kunnen worden samengevoegd. Als u twee lijsten in één wilt samenvoegen, gebruikt u List.append. Als u meer dan twee lijsten wilt samenvoegen, gebruikt u List.concat.
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
Vouw- en scanbewerkingen
Bij sommige lijstbewerkingen zijn afhankelijkheden tussen alle lijstelementen betrokken. De vouw- en scanbewerkingen zijn zoals List.iter
en List.map
in dat u een functie aanroept op elk element, maar deze bewerkingen bieden een extra parameter, de accumulator die informatie via de berekening bevat.
Hiermee List.fold
kunt u een berekening uitvoeren op een lijst.
In het volgende codevoorbeeld ziet u hoe List.fold wordt gebruikt om verschillende bewerkingen uit te voeren.
De lijst wordt doorkruist; de accumulator acc
is een waarde die wordt doorgegeven wanneer de berekening wordt voortgezet. Het eerste argument neemt de accumulator en het lijstelement en retourneert het tussentijdse resultaat van de berekening voor dat lijstelement. Het tweede argument is de initiële waarde van de accumulator.
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])
De versies van deze functies met een cijfer in de functienaam werken op meer dan één lijst. List.fold2 voert bijvoorbeeld berekeningen uit op twee lijsten.
In het volgende voorbeeld ziet u het gebruik van List.fold2
.
// 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
en List.scan verschilt in dat List.fold
retourneert de uiteindelijke waarde van de extra parameter, maar List.scan
retourneert de lijst met de tussenliggende waarden (samen met de uiteindelijke waarde) van de extra parameter.
Elk van deze functies bevat een omgekeerde variatie, bijvoorbeeld List.foldBack, die verschilt in de volgorde waarin de lijst wordt doorkruist en de volgorde van de argumenten. List.fold
En List.foldBack
hebben variaties, List.fold2 en List.foldBack2, die twee lijsten met gelijke lengte hebben. De functie die op elk element wordt uitgevoerd, kan overeenkomende elementen van beide lijsten gebruiken om een bepaalde actie uit te voeren. De elementtypen van de twee lijsten kunnen verschillen, zoals in het volgende voorbeeld, waarin de ene lijst transactiebedragen voor een bankrekening bevat en de andere lijst het type transactie bevat: storting of intrekking.
// 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
Voor een berekening zoals optellen en List.foldBack
hetzelfde effect hebben omdat List.fold
het resultaat niet afhankelijk is van de volgorde van doorkruising. In het volgende voorbeeld List.foldBack
wordt gebruikt om de elementen in een lijst toe te voegen.
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])
In het volgende voorbeeld wordt het voorbeeld van de bankrekening geretourneerd. Deze keer wordt een nieuw transactietype toegevoegd: een renteberekening. Het eindsaldo is nu afhankelijk van de volgorde van transacties.
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
De functie List.reduce lijkt enigszins op List.fold
en List.scan
, behalve dat in plaats van een afzonderlijke accumulator een List.reduce
functie te geven die twee argumenten van het elementtype in plaats van slechts één gebruikt, en een van deze argumenten fungeert als de accumulator, wat betekent dat het tussenliggende resultaat van de berekening wordt opgeslagen. List.reduce
begint met het gebruik van de eerste twee lijstelementen en gebruikt vervolgens het resultaat van de bewerking samen met het volgende element. Omdat er geen afzonderlijke accumulator is die een eigen type heeft, List.reduce
kan alleen worden gebruikt als List.fold
de accumulator en het elementtype hetzelfde type hebben. De volgende code demonstreert het gebruik van List.reduce
. List.reduce
genereert een uitzondering als de opgegeven lijst geen elementen bevat.
In de volgende code krijgt de eerste aanroep van de lambda-expressie de argumenten 2 en 4 en wordt 6 geretourneerd. De volgende aanroep krijgt de argumenten 6 en 10, dus het resultaat is 16.
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
Converteren tussen lijsten en andere verzamelingstypen
De List
module biedt functies voor het converteren naar en van zowel reeksen als matrices. Als u wilt converteren naar of van een reeks, gebruikt u List.toSeq of List.ofSeq. Als u wilt converteren naar of van een matrix, gebruikt u List.toArray of List.ofArray.
Aanvullende bewerkingen
Zie de bibliotheekverwijzingsonderwerplijstmodule voor meer informatie over aanvullende bewerkingen op lijsten.