Listor
En lista i F# är en ordnad, oföränderlig serie element av samma typ. Om du vill utföra grundläggande åtgärder i listor använder du funktionerna i modulen Lista.
Skapa och initiera listor
Du kan definiera en lista genom att uttryckligen visa elementen avgränsade med semikolon och omges av hakparenteser, enligt följande kodrad.
let list123 = [ 1; 2; 3 ]
Du kan också placera radbrytningar mellan element, i vilket fall semikolonen är valfria. Den senare syntaxen kan resultera i mer läsbar kod när elementinitieringsuttrycken är längre eller när du vill ta med en kommentar för varje element.
let list123 = [ 1; 2; 3 ]
Normalt måste alla listelement vara av samma typ. Ett undantag är att en lista där elementen anges som en bastyp kan ha element som är härledda typer. Därför är följande acceptabelt, eftersom både Button
och CheckBox
härleds från Control
.
let myControlList: Control list = [ new Button(); new CheckBox() ]
Du kan också definiera listelement med hjälp av ett intervall som anges av heltal avgränsade med intervalloperatorn (..
), enligt följande kod.
let list1 = [ 1..10 ]
En tom lista anges av ett par hakparenteser utan något mellan dem.
// An empty list.
let listEmpty = []
Du kan också använda ett sekvensuttryck för att skapa en lista. Mer information finns i Sekvensuttryck . Följande kod skapar till exempel en lista över kvadrater med heltal från 1 till 10.
let listOfSquares = [ for i in 1..10 -> i * i ]
Operatorer för att arbeta med listor
Du kan koppla element till en lista med hjälp av operatorn ::
(cons). Om list1
är [2; 3; 4]
skapas list2
följande kod som [100; 2; 3; 4]
.
let list2 = 100 :: list1
Du kan sammanfoga listor som har kompatibla typer med hjälp av operatorn @
, som i följande kod. Om list1
är [2; 3; 4]
och list2
är [100; 2; 3; 4]
skapas list3
den här koden som [2; 3; 4; 100; 2; 3; 4]
.
let list3 = list1 @ list2
Funktioner för att utföra åtgärder på listor finns i modulen Lista.
Eftersom listor i F# är oföränderliga genererar alla ändringsåtgärder nya listor i stället för att ändra befintliga listor.
Listor i F# implementeras som singly länkade listor, vilket innebär att åtgärder som endast har åtkomst till listans huvud är O(1) och elementåtkomst är O(n).
Egenskaper
Listtypen stöder följande egenskaper:
Property | Type | Beskrivning |
---|---|---|
Huvud | 'T |
Det första elementet. |
Tom | 'T list |
En statisk egenskap som returnerar en tom lista av lämplig typ. |
IsEmpty | bool |
true om listan inte har några element. |
Artikel | 'T |
Elementet vid det angivna indexet (nollbaserat). |
Längd | int |
Antalet element. |
Svans | 'T list |
Listan utan det första elementet. |
Här följer några exempel på hur du använder de här egenskaperna.
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))
Använda listor
Med programmering med listor kan du utföra komplexa åtgärder med en liten mängd kod. I det här avsnittet beskrivs vanliga åtgärder i listor som är viktiga för funktionell programmering.
Rekursion med listor
Listor passar unikt för rekursiva programmeringstekniker. Överväg en åtgärd som måste utföras på varje element i en lista. Du kan göra detta rekursivt genom att arbeta på listans huvud och sedan skicka svansen i listan, som är en mindre lista som består av den ursprungliga listan utan det första elementet, tillbaka igen till nästa rekursionsnivå.
Om du vill skriva en sådan rekursiv funktion använder du cons-operatorn (::
) i mönstermatchning, vilket gör att du kan separera huvudet på en lista från svansen.
I följande kodexempel visas hur du använder mönstermatchning för att implementera en rekursiv funktion som utför åtgärder i en lista.
let rec sum list =
match list with
| head :: tail -> head + sum tail
| [] -> 0
Den tidigare koden fungerar bra för små listor, men för större listor kan den spilla över stacken. Följande kod förbättrar den här koden med hjälp av ett ackumulatorargument, en standardteknik för att arbeta med rekursiva funktioner. Användningen av ackumulatorargumentet gör funktionen tail rekursiv, vilket sparar stackutrymme.
let sum list =
let rec loop list acc =
match list with
| head :: tail -> loop tail (acc + head)
| [] -> acc
loop list 0
Funktionen RemoveAllMultiples
är en rekursiv funktion som tar två listor. Den första listan innehåller de tal vars multiplar kommer att tas bort och den andra listan är den lista som talen ska tas bort från. Koden i följande exempel använder den här rekursiva funktionen för att eliminera alla icke-primära tal från en lista och lämnar en lista med primtal som resultat.
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)
Utdata är följande:
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]
Modulfunktioner
Modulen Lista innehåller funktioner som har åtkomst till elementen i en lista. Huvudelementet är det snabbaste och enklaste att komma åt. Använd egenskapen Head eller modulfunktionen List.head. Du kan komma åt slutet av en lista med hjälp av egenskapen Tail eller funktionen List.tail . Om du vill hitta ett element efter index använder du funktionen List.nth . List.nth
går igenom listan. Därför är det O(n). Om koden används List.nth
ofta kanske du vill överväga att använda en matris i stället för en lista. Elementåtkomst i matriser är O(1).
Booleska åtgärder i listor
Funktionen List.isEmpty avgör om en lista har några element.
Funktionen List.exists tillämpar ett booleskt test på element i en lista och returnerar true
om något element uppfyller testet. List.exists2 är liknande men fungerar på efterföljande par med element i två listor.
Följande kod visar användningen av 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)
Utdata är följande:
For list [0; 1; 2; 3], contains zero is true
I följande exempel visas användningen av 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
Utdata är följande:
Lists [1; 2; 3; 4; 5] and [5; 4; 3; 2; 1] have at least one equal element at the same position.
Du kan använda List.forall om du vill testa om alla element i en lista uppfyller ett villkor.
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])
Utdata är följande:
true
false
På samma sätt avgör List.forall2 om alla element i motsvarande positioner i två listor uppfyller ett booleskt uttryck som omfattar varje elementpar.
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])
Utdata är följande:
true
false
Sortera åtgärder på listor
Sorteringslistorna List.sort, List.sortBy och List.sortWith. Sorteringsfunktionen avgör vilken av dessa tre funktioner som ska användas. List.sort
använder standardmässig allmän jämförelse. Allmän jämförelse använder globala operatorer baserat på den generiska jämförelsefunktionen för att jämföra värden. Det fungerar effektivt med en mängd olika elementtyper, till exempel enkla numeriska typer, tupplar, poster, diskriminerade fackföreningar, listor, matriser och alla typer som implementerar System.IComparable
. För typer som implementerar System.IComparable
använder System.IComparable.CompareTo()
allmän jämförelse funktionen. Allmän jämförelse fungerar också med strängar, men använder en kulturoberoende sorteringsordning. Allmän jämförelse bör inte användas för typer som inte stöds, till exempel funktionstyper. Dessutom är prestandan för den allmänna standardjämförelsen bäst för små strukturerade typer. För större strukturerade typer som måste jämföras och sorteras ofta bör du överväga att implementera System.IComparable
och tillhandahålla en effektiv implementering av System.IComparable.CompareTo()
metoden.
List.sortBy
tar en funktion som returnerar ett värde som används som sorteringsvillkor och List.sortWith
tar en jämförelsefunktion som argument. Dessa två senare funktioner är användbara när du arbetar med typer som inte stöder jämförelse, eller när jämförelsen kräver mer komplex jämförelsesemantik, som när det gäller kulturmedvetna strängar.
I följande exempel visas användningen av List.sort
.
let sortedList1 = List.sort [1; 4; 8; -2; 5]
printfn "%A" sortedList1
Utdata är följande:
[-2; 1; 4; 5; 8]
I följande exempel visas användningen av List.sortBy
.
let sortedList2 = List.sortBy (fun elem -> abs elem) [1; 4; 8; -2; 5]
printfn "%A" sortedList2
Utdata är följande:
[1; -2; 4; 5; 8]
I nästa exempel visas användningen av List.sortWith
. I det här exemplet används den anpassade jämförelsefunktionen compareWidgets
för att först jämföra ett fält av en anpassad typ och sedan ett annat när värdena för det första fältet är lika.
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
Utdata är följande:
[{ID = 92;
Rev = 1;}; {ID = 92;
Rev = 1;}; {ID = 100;
Rev = 2;}; {ID = 100;
Rev = 5;}; {ID = 110;
Rev = 1;}]
Sökåtgärder i listor
Många sökåtgärder stöds för listor. Det enklaste, List.find, gör att du kan hitta det första elementet som matchar ett visst villkor.
Följande kodexempel visar användningen av List.find
för att hitta det första talet som är delbart med 5 i en lista.
let isDivisibleBy number elem = elem % number = 0
let result = List.find (isDivisibleBy 5) [ 1 .. 100 ]
printfn "%d " result
Resultatet är 5.
Om elementen måste transformeras först anropar du List.pick, som tar en funktion som returnerar ett alternativ och letar efter det första alternativvärdet som är Some(x)
. I stället för att returnera elementet List.pick
returnerar resultatet x
. Om inget matchande element hittas List.pick
genererar System.Collections.Generic.KeyNotFoundException
. Följande kod visar användningen av 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
Utdata är följande:
"b"
En annan grupp med sökåtgärder, List.tryFind och relaterade funktioner, returnerar ett alternativvärde. Funktionen List.tryFind
returnerar det första elementet i en lista som uppfyller ett villkor om ett sådant element finns, men alternativvärdet None
om inte. Varianten List.tryFindIndex returnerar elementets index, om ett hittas, i stället för själva elementet. Dessa funktioner visas i följande kod.
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."
Utdata är följande:
The first even value is 22.
The first even value is at position 8.
Aritmetiska åtgärder på listor
Vanliga aritmetiska åtgärder som summa och medelvärde är inbyggda i listmodulen. Om du vill arbeta med List.sum måste listelementtypen ha stöd för operatorn +
och ha ett nollvärde. Alla inbyggda aritmetiska typer uppfyller dessa villkor. För att fungera med List.average måste elementtypen ha stöd för division utan rest, vilket exkluderar integraltyper men tillåter flyttalstyper. Funktionerna List.sumBy och List.averageBy har en funktion som parameter, och den här funktionens resultat används för att beräkna värdena för summan eller medelvärdet.
Följande kod visar användningen av List.sum
, List.sumBy
och 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
Utdata är 1.000000
.
Följande kod visar användningen av List.averageBy
.
let avg2 = List.averageBy (fun elem -> float elem) [1 .. 10]
printfn "%f" avg2
Utdata är 5.5
.
Listor och tupplar
Listor som innehåller tupplar kan manipuleras av zip- och packa upp funktioner. Dessa funktioner kombinerar två listor med enkla värden i en lista med tupplar eller separerar en lista med tupplar i två listor med enkla värden. Den enklaste List.zip funktionen tar två listor med enkla element och skapar en enda lista med tuppelpar. En annan version, List.zip3, tar tre listor med enskilda element och skapar en enda lista över tupplar som har tre element. I följande kodexempel visas användningen av List.zip
.
let list1 = [ 1; 2; 3 ]
let list2 = [ -1; -2; -3 ]
let listZip = List.zip list1 list2
printfn "%A" listZip
Utdata är följande:
[(1, -1); (2, -2); (3; -3)]
I följande kodexempel visas användningen av List.zip3
.
let list3 = [ 0; 0; 0]
let listZip3 = List.zip3 list1 list2 list3
printfn "%A" listZip3
Utdata är följande:
[(1, -1, 0); (2, -2, 0); (3, -3, 0)]
Motsvarande uppackade versioner, List.unzip och List.unzip3, tar listor över tupplar och returlistor i en tupplar, där den första listan innehåller alla element som var först i varje tupplar och den andra listan innehåller det andra elementet i varje tupplar och så vidare.
Följande kodexempel visar användningen av List.unzip.
let lists = List.unzip [(1,2); (3,4)]
printfn "%A" lists
printfn "%A %A" (fst lists) (snd lists)
Utdata är följande:
([1; 3], [2; 4])
[1; 3] [2; 4]
I följande kodexempel visas användningen av List.unzip3.
let listsUnzip3 = List.unzip3 [(1,2,3); (4,5,6)]
printfn "%A" listsUnzip3
Utdata är följande:
([1; 4], [2; 5], [3; 6])
Arbeta med listelement
F# stöder en mängd olika åtgärder för listelement. Det enklaste är List.iter, som gör att du kan anropa en funktion i varje element i en lista. Varianter inkluderar List.iter2, som gör att du kan utföra en åtgärd på element i två listor, List.iteri, som är som List.iter
förutom att indexet för varje element skickas som ett argument till funktionen som anropas för varje element och List.iteri2, vilket är en kombination av funktionerna List.iter2
i och List.iteri
. Följande kodexempel illustrerar dessa funktioner.
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
Utdata är följande:
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
En annan funktion som ofta används för att transformera listelement är List.map, som gör att du kan använda en funktion för varje element i en lista och placera alla resultat i en ny lista. List.map2 och List.map3 är varianter som tar flera listor. Du kan också använda List.mapi och List.mapi2, om funktionen utöver elementet måste skickas indexet för varje element. Den enda skillnaden mellan List.mapi2
och List.mapi
är att List.mapi2
fungerar med två listor. I följande exempel visas List.map.
let list1 = [1; 2; 3]
let newList = List.map (fun x -> x + 1) list1
printfn "%A" newList
Utdata är följande:
[2; 3; 4]
I följande exempel visas användningen av 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
Utdata är följande:
[5; 7; 9]
I följande exempel visas användningen av List.map3
.
let newList2 = List.map3 (fun x y z -> x + y + z) list1 list2 [2; 3; 4]
printfn "%A" newList2
Utdata är följande:
[7; 10; 13]
I följande exempel visas användningen av List.mapi
.
let newListAddIndex = List.mapi (fun i x -> x + i) list1
printfn "%A" newListAddIndex
Utdata är följande:
[1; 3; 5]
I följande exempel visas användningen av List.mapi2
.
let listAddTimesIndex = List.mapi2 (fun i x y -> (x + y) * i) list1 list2
printfn "%A" listAddTimesIndex
Utdata är följande:
[0; 7; 18]
List.collect är som List.map
, förutom att varje element skapar en lista och alla dessa listor sammanfogas till en slutlig lista. I följande kod genererar varje element i listan tre tal. Alla dessa samlas in i en lista.
let collectList = List.collect (fun x -> [for i in 1..3 -> x * i]) list1
printfn "%A" collectList
Utdata är följande:
[1; 2; 3; 2; 4; 6; 3; 6; 9]
Du kan också använda List.filter, som tar ett booleskt villkor och skapar en ny lista som endast består av element som uppfyller det angivna villkoret.
let evenOnlyList = List.filter (fun x -> x % 2 = 0) [1; 2; 3; 4; 5; 6]
Den resulterande listan är [2; 4; 6]
.
En kombination av karta och filter, List.choose gör att du kan transformera och välja element samtidigt. List.choose
tillämpar en funktion som returnerar ett alternativ för varje element i en lista och returnerar en ny lista med resultat för element när funktionen returnerar alternativvärdet Some
.
Följande kod visar användningen av List.choose
för att välja versaler i en lista med ord.
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
Utdata är följande:
["Rome's"; "Bob's"]
Arbeta på flera listor
Listor kan kopplas samman. Om du vill koppla två listor till en använder du List.append. Om du vill ansluta fler än två listor använder du 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
Vik- och genomsökningsåtgärder
Vissa liståtgärder omfattar beroenden mellan alla listelement. Viknings- och genomsökningsåtgärderna är som List.iter
och List.map
i så fall anropar du en funktion för varje element, men de här åtgärderna ger ytterligare en parameter som kallas ackumulatorn som innehåller information via beräkningen.
Använd List.fold
för att utföra en beräkning i en lista.
Följande kodexempel visar användningen av List.fold för att utföra olika åtgärder.
Listan har bläddrades. ackumulatorn acc
är ett värde som skickas när beräkningen fortsätter. Det första argumentet tar ackumulatorn och listelementet och returnerar interimsresultatet för beräkningen för listelementet. Det andra argumentet är det ursprungliga värdet för ackumulatorn.
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 versioner av dessa funktioner som har en siffra i funktionsnamnet fungerar på fler än en lista. List.fold2 utför till exempel beräkningar på två listor.
I följande exempel visas användningen av 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
och List.scan skiljer sig åt däri returnerar det List.fold
slutliga värdet för den extra parametern, men List.scan
returnerar listan över mellanliggande värden (tillsammans med det slutliga värdet) för den extra parametern.
Var och en av dessa funktioner innehåller en omvänd variant, till exempel List.foldBack, som skiljer sig i vilken ordning listan bläddras och argumentens ordning. Dessutom, List.fold
och List.foldBack
har varianter, List.fold2 och List.foldBack2, som tar två listor med samma längd. Funktionen som körs på varje element kan använda motsvarande element i båda listorna för att utföra en åtgärd. Elementtyperna i de två listorna kan vara olika, som i följande exempel, där en lista innehåller transaktionsbelopp för ett bankkonto, och den andra listan innehåller typen av transaktion: insättning eller uttag.
// 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
För en beräkning som summering List.fold
och List.foldBack
har samma effekt eftersom resultatet inte är beroende av bläddringsordningen. I följande exempel List.foldBack
används för att lägga till elementen i en lista.
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])
Följande exempel återgår till bankkontoexemplet. Den här gången läggs en ny transaktionstyp till: en ränteberäkning. Slutsaldot beror nu på transaktionsordningen.
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
Funktionen List.reduce är ungefär som List.fold
och List.scan
, förutom att i stället för att skicka runt en separat ackumulator, List.reduce
tar en funktion som tar två argument av elementtypen i stället för bara en, och ett av dessa argument fungerar som ackumulator, vilket innebär att den lagrar det mellanliggande resultatet av beräkningen. List.reduce
startar genom att använda de två första listelementen och använder sedan resultatet av åtgärden tillsammans med nästa element. Eftersom det inte finns en separat ackumulator som har sin egen typ, List.reduce
kan endast användas i stället för List.fold
när ackumulatorn och elementtypen har samma typ. Följande kod visar användningen av List.reduce
. List.reduce
genererar ett undantag om den angivna listan inte har några element.
I följande kod får det första anropet till lambda-uttrycket argumenten 2 och 4 och returnerar 6, och nästa anrop får argumenten 6 och 10, så resultatet är 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
Konvertera mellan listor och andra samlingstyper
Modulen List
innehåller funktioner för att konvertera till och från både sekvenser och matriser. Om du vill konvertera till eller från en sekvens använder du List.toSeq eller List.ofSeq. Om du vill konvertera till eller från en matris använder du List.toArray eller List.ofArray.
Ytterligare åtgärder
Mer information om ytterligare åtgärder i listor finns i biblioteksreferensavsnittet Listmodul.