Arrays (F#)

Arrays sind nullbasierte, änderbare Sequenzen fester Größe von aufeinander folgenden Datenelementen, die alle den gleichen Typ aufweisen.

Erstellen von Arrays

Sie können Arrays auf verschiedene Arten erstellen. Sie können ein kleines Array erstellen, indem Sie aufeinanderfolgende durch Semikolons getrennte Werte zwischen [| und |] aufführen, wie in den folgenden Beispielen gezeigt.

let array1 = [| 1; 2; 3 |]

Sie können auch jedes Element in einer eigenen Zeile anordnen. In diesem Fall ist das Semikolontrennzeichen optional.

let array1 = 
    [|
        1
        2
        3
     |]

Der Typ der Arrayelemente wird von den verwendeten Literalen abgeleitet, und er muss konsistent sein. Somit verursacht der folgende Code einen Fehler, da 1.0 ein Gleitkommawert ist und 2 und 3 ganze Zahlen sind.

// Causes an error.
// let array2 = [| 1.0; 2; 3 |] 

Sie können Arrays mithilfe von Sequenzausdrücken erstellen. Im folgenden Beispiel wird ein Array aus den Quadraten von ganzen Zahlen zwischen 1 und 10 erstellt.

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

Verwenden Sie Array.zeroCreate, um ein Array zu erstellen, dessen sämtliche Elemente mit 0 (null) initialisiert sind.

let arrayOfTenZeroes : int array = Array.zeroCreate 10

Zugreifen auf Elemente

Auf Arrayelemente können Sie mit dem Punktoperator (.) und mit Klammern ([ und ]) zugreifen.

array1.[0]

Arrayindizes beginnen bei 0.

Der Zugriff auf Arrayelemente kann auch mit Slicenotation erfolgen, die es Ihnen ermöglicht, einen Teilbereich des Arrays anzugeben. Im Folgenden erhalten Sie Beispiele für Slicenotation.

// Accesses elements from 0 to 2.
array1.[0..2]  
// Accesses elements from the beginning of the array to 2.
array1.[..2] 
// Accesses elements from 2 to the end of the array.
array1.[2..] 

Bei Verwendung von Slicenotation wird eine neue Kopie des Arrays erstellt.

Arraytypen und Module

Alle F#-Arrays sind vom .NET Framework-Typ Array. Daher unterstützen F#-Arrays alle in Array verfügbaren Funktionen.

Das Bibliotheksmodul Microsoft.FSharp.Collections.Array unterstützt Operationen auf eindimensionalen Arrays. Die Module Array2D, Array3D und Array4D enthalten Funktionen, die Operationen für Arrays mit zwei, drei bzw. vier Dimensionen unterstützen. Mit Array können Sie Arrays mit einem Rang größer vier erstellen.

Einfache Funktionen

Array.get ruft ein Element ab. Array.length gibt die Länge eines Arrays an. Array.set legt ein Element auf einen angegebenen Wert fest. Im folgenden Codebeispiel wird die Verwendung dieser Funktionen veranschaulicht.

let array1 = Array.create 10 ""
for i in 0 .. array1.Length - 1 do
    Array.set array1 i (i.ToString())
for i in 0 .. array1.Length - 1 do
    printf "%s " (Array.get array1 i)

Die Ausgabe lautet wie folgt.

0 1 2 3 4 5 6 7 8 9

Funktionen, die Arrays generieren

Mehrere Funktionen erstellen Arrays, ohne ein vorhandenes Array zu erfordern. Array.empty erstellt ein neues Array ohne Elemente. Array.create erstellt ein Array einer angegebenen Größe und legt alle Elemente auf bereitgestellte Werte fest. Array.init erstellt ein Array unter Verwendung einer Dimensionen und einer Funktion zur Erstellung von Elementen. Array.zeroCreate erstellt ein Array, in dem alle Elemente auf den Wert 0 für den Typ des Arrays initialisiert werden. Dieser Code demonstriert die Funktionen.

let myEmptyArray = Array.empty
printfn "Length of empty array: %d" myEmptyArray.Length

printfn "Array of floats set to 5.0: %A" (Array.create 10 5.0)
printfn "Array of squares: %A" (Array.init 10 (fun index -> index * index))
let (myZeroArray : float array) = Array.zeroCreate 10

Die Ausgabe lautet wie folgt.

Length of empty array: 0
Area of floats set to 5.0: [|5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0|]
Array of squares: [|0; 1; 4; 9; 16; 25; 36; 49; 64; 81|]

Array.copy erstellt ein neues Array, das Elemente enthält, die aus einem vorhandenen Array kopiert werden. Beachten Sie, dass die Kopie eine flache Kopie ist, d. h., wenn der Elementtyp ein Verweistyp ist, wird nur der Verweis, nicht das zugrunde liegende Objekt kopiert. Dies wird im folgenden Codebeispiel veranschaulicht.

open System.Text

let firstArray : StringBuilder array = Array.init 3 (fun index -> new StringBuilder(""))
let secondArray = Array.copy firstArray
// Reset an element of the first array to a new value.
firstArray.[0] <- new StringBuilder("Test1")
// Change an element of the first array.
firstArray.[1].Insert(0, "Test2") |> ignore
printfn "%A" firstArray
printfn "%A" secondArray

Der obige Code gibt Folgendes aus:

[|Test1; Test2; |]
[|; Test2; |]

Die Zeichenfolge Test1 wird nur im ersten Array angezeigt, da der Vorgang der Erstellung eines neuen Elements, den Verweis in firstArray überschreibt, aber sich nicht auf den ursprünglichen Verweis auf eine leere Zeichenfolge auswirkt, die immer noch im secondArray vorhanden ist. Die Zeichenfolge Test2 wird in beiden Arrays angezeigt, da sich die Insert-Operation für den StringBuilder-Typ auf das zugrundeliegende StringBuilder-Objekt auswirkt, auf das in beiden Arrays verwiesen wird.

Array.sub generiert ein neues Array aus einem Teilbereich eines Arrays. Sie geben den Teilbereich an, indem Sie den Startindex und die Länge bereitstellen. Das folgende Codebeispiel veranschaulicht die Verwendung von Array.sub.

let a1 = [| 0 .. 99 |]
let a2 = Array.sub a1 5 10
printfn "%A" a2

Die Ausgabe zeigt an, dass das Unterfeld bei Element "5" beginnt und 10 Elemente enthält.

[|5; 6; 7; 8; 9; 10; 11; 12; 13; 14|]

Array.append erstellt ein neues Array, indem zwei vorhandene Arrays kombiniert werden.

Der folgende Code stellt Array.append dar.

printfn "%A" (Array.append [| 1; 2; 3|] [| 4; 5; 6|])

Die Ausgabe des vorhergehenden Codes entspricht dem Folgenden.

[|1; 2; 3; 4; 5; 6|]

Array.choose wählt Elemente eines Arrays aus, die in einem neuen Array enthalten sein sollen. Der folgende Code stellt Array.choose dar. Beachten Sie, dass der Elementtyp des Arrays nicht zum Typ des Werts passen muss, der im Optionstyp zurückgegeben wurde. In diesem Beispiel ist der Elementtyp int, und die Option ist das Ergebnis einer Polynomfunktion (elem*elem - 1) als Gleitkommazahl.

printfn "%A" (Array.choose (fun elem -> if elem % 2 = 0 then
                                            Some(float (elem*elem - 1))
                                        else
                                            None) [| 1 .. 10 |])

Die Ausgabe des vorhergehenden Codes entspricht dem Folgenden.

[|3.0; 15.0; 35.0; 63.0; 99.0|]

Array.collect führt für jedes Arrayelement eines vorhandenen Arrays eine angegebene Funktion aus, sammelt dann die von der Funktion generierten Elemente und kombiniert sie zu einem neuen Array. Der folgende Code veranschaulicht Array.collect.

printfn "%A" (Array.collect (fun elem -> [| 0 .. elem |]) [| 1; 5; 10|])

Die Ausgabe des vorhergehenden Codes entspricht dem Folgenden.

[|0; 1; 0; 1; 2; 3; 4; 5; 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]

Array.concat nimmt eine Sequenz von Arrays und kombiniert sie in ein einzelnes Array. Der folgende Code veranschaulicht Array.concat.

let multiplicationTable max = seq { for i in 1 .. max -> [| for j in 1 .. max -> (i, j, i*j) |] }
printfn "%A" (Array.concat (multiplicationTable 3))

Die Ausgabe des vorhergehenden Codes entspricht dem Folgenden.

[|(1, 1, 1); (1, 2, 2); (1, 3, 3); (2, 1, 2); (2, 2, 4); (2, 3, 6); (3, 1, 3);
  (3, 2, 6); (3, 3, 9)|]

Array.filter nimmt eine boolesche Bedingungsfunktion und generiert ein neues Array, das nur die Elemente des Eingabearrays enthält, für die die Bedingung den Wert "true" hat. Der folgende Code stellt Array.filter dar.

printfn "%A" (Array.filter (fun elem -> elem % 2 = 0) [| 1 .. 10|])

Die Ausgabe des vorhergehenden Codes entspricht dem Folgenden.

[|2; 4; 6; 8; 10|]

Array.rev generiert ein neues Array, indem die Reihenfolge eines vorhandenen Arrays umgekehrt wird. Der folgende Code stellt Array.rev dar.

let stringReverse (s: string) =
    System.String(Array.rev (s.ToCharArray()))

printfn "%A" (stringReverse("!dlrow olleH"))

Die Ausgabe des vorhergehenden Codes entspricht dem Folgenden.

"Hello world!"

Wie im folgenden Beispiel gezeigt wird, können Sie Funktionen im Arraymodul, das Arrays mit dem Pipelineoperator (| >) transformiert, leicht kombinieren.

[| 1 .. 10 |]
|> Array.filter (fun elem -> elem % 2 = 0)
|> Array.choose (fun elem -> if (elem <> 8) then Some(elem*elem) else None)
|> Array.rev
|> printfn "%A"

Ausgabe:

[|100; 36; 16; 4|]

Mehrdimensionale Arrays

Ein mehrdimensionales Array kann erstellt werden, jedoch gibt es keine Syntax zum Schreiben eines mehrdimensionalen Arrayliterals. Verwenden Sie den array2D-Operator, um ein Array aus einer Sequenz von Sequenzen von Arrayelementen zu erstellen. Die Sequenzen können Array- oder Listenliterale sein. Im folgenden Code wird z. B. ein zweidimensionales Array erstellt.

let my2DArray = array2D [ [ 1; 0]; [0; 1] ]

Sie können mithilfe der Funktion Array2D.init auch Arrays mit zwei Dimensionen initialisieren. Ähnliche Funktionen sind für Arrays mit drei und vier Dimensionen verfügbar. Diese Funktionen nehmen eine Funktion, die zum Erstellen der Elemente verwendet wird. Zum Erstellen eines zweidimensionalen Arrays mit Elementen, die auf einen Anfangswert festgelegt sind statt eine Funktion anzugeben, verwenden Sie die Array2D.create-Funktion, die auch für Arrays mit bis zu vier Dimensionen verfügbar ist. Im folgenden Codebeispiel wird die Erstellung eines Arrays von Arrays mit den gewünschten Elementen veranschaulicht, und dann wird mit Array2D.init das gewünschte zweidimensionale Array generiert.

let arrayOfArrays = [| [| 1.0; 0.0 |]; [|0.0; 1.0 |] |]
let twoDimensionalArray = Array2D.init 2 2 (fun i j -> arrayOfArrays.[i].[j]) 

Arrayindizierung und das Aufteilen von Syntax in Slices werden für Arrays bis zu Rang 4 unterstützt. Wenn Sie einen Index in mehreren Dimensionen angeben, trennen Sie die Indizes mithilfe von Kommas, wie im folgenden Codebeispiel illustriert.

twoDimensionalArray.[0, 1] <- 1.0

Der Typ eines zweidimensionalen Arrays wird als <type>[,] (z. B.,int[,], double[,]) geschrieben, und der Typ eines dreidimensionalen Arrays wird als <type>[,,] usw. für Arrays mit mehr Dimensionen geschrieben.

Nur eine Teilmenge der Funktionen für eindimensionale Arrays ist auch für mehrdimensionale Arrays verfügbar. Weitere Informationen finden Sie unter Collections.Array-Modul (F#), Collections.Array2D-Modul (F#), Collections.Array3D-Modul (F#) und Collections.Array4D-Modul (F#).

Boolesche Funktionen für Arrays

Die Funktionen Array.exists und Array.exists2 testen Elemente in einem bzw. zwei Arrays. Diese Funktionen akzeptieren eine Testfunktion und geben true zurück, wenn die Bedingung von einem Element (oder Elementpaaren für Array.exists2) erfüllt wird.

Das folgende Codebeispiel veranschaulicht die Verwendung von Array.exists und Array.exists2. In diesen Beispielen werden neue Funktionen durch das Übernehmen von nur einem der Argumente, in diesen Fällen das Funktionsargument, erstellt.

let allNegative = Array.exists (fun elem -> abs (elem) = elem) >> not
printfn "%A" (allNegative [| -1; -2; -3 |])
printfn "%A" (allNegative [| -10; -1; 5 |])
printfn "%A" (allNegative [| 0 |])
let haveEqualElement = Array.exists2 (fun elem1 elem2 -> elem1 = elem2)
printfn "%A" (haveEqualElement [| 1; 2; 3 |] [| 3; 2; 1|])

Die Ausgabe des vorhergehenden Codes entspricht dem Folgenden.

true
false
false
true

Auf ähnliche Weise testet die Array.forall-Funktion ein Array, um zu bestimmen, ob jedes Element eine boolesche Bedingung erfüllt. Der Variation Array.forall2 erfüllt denselben Zweck mit einer booleschen Funktion, die Elemente zweier Arrays gleicher Länge enthält. Im folgenden Code wird die Verwendung dieser Funktionen veranschaulicht.

let allPositive = Array.forall (fun elem -> elem > 0)
printfn "%A" (allPositive [| 0; 1; 2; 3 |])
printfn "%A" (allPositive [| 1; 2; 3 |])
let allEqual = Array.forall2 (fun elem1 elem2 -> elem1 = elem2)
printfn "%A" (allEqual [| 1; 2 |] [| 1; 2 |])
printfn "%A" (allEqual [| 1; 2 |] [| 2; 1 |])

Die Ausgabe dieser Beispiele lautet folgendermaßen.

false
true
true
false

Durchsuchen von Arrays

Array.find nimmt eine boolesche Funktion und gibt das erste Element zurück, für das die Funktion true zurückgibt, oder löst einen KeyNotFoundException aus wenn kein entsprechendes Element für die Bedingung gefunden wird. Array.findIndex entspricht Array.find, außer dass der Index des Elements statt dem Element selbst zurückgegeben wird.

Der folgende Code sucht mithilfe von Array.find und Array.findIndex eine Zahl, die sowohl ein perfektes Quadrat als auch perfekter Cube ist.

let arrayA = [| 2 .. 100 |]
let delta = 1.0e-10
let isPerfectSquare (x:int) =
    let y = sqrt (float x)
    abs(y - round y) < delta
let isPerfectCube (x:int) =
    let y = System.Math.Pow(float x, 1.0/3.0)
    abs(y - round y) < delta
let element = Array.find (fun elem -> isPerfectSquare elem && isPerfectCube elem) arrayA
let index = Array.findIndex (fun elem -> isPerfectSquare elem && isPerfectCube elem) arrayA
printfn "The first element that is both a square and a cube is %d and its index is %d." element index

Die Ausgabe lautet wie folgt.

The first element that is both a square and a cube is 64 and its index is 62.

Array.tryFind entspricht Array.find, außer, dass das Ergebnis ein Optionstyp ist und None zurückgegeben wird, wenn kein Element gefunden wird. Array.tryFind sollte statt Array.find verwendet werden, wenn nicht bekannt ist, ob ein entsprechendes Element im Array vorhanden ist. Array.tryFindIndex entspricht Array.findIndex, außer, dass der Optionstyp der Rückgabewert ist. Wenn kein Element gefunden wird, lautet die Option None.

Das folgende Codebeispiel veranschaulicht die Verwendung von Array.tryFind. Dieser Code hängt vom vorherigen Code ab.

let delta = 1.0e-10
let isPerfectSquare (x:int) =
    let y = sqrt (float x)
    abs(y - round y) < delta
let isPerfectCube (x:int) =
    let y = System.Math.Pow(float x, 1.0/3.0)
    abs(y - round y) < delta
let lookForCubeAndSquare array1 =
    let result = Array.tryFind (fun elem -> isPerfectSquare elem && isPerfectCube elem) array1
    match result with
    | Some x -> printfn "Found an element: %d" x
    | None -> printfn "Failed to find a matching element."

lookForCubeAndSquare [| 1 .. 10 |]
lookForCubeAndSquare [| 100 .. 1000 |]
lookForCubeAndSquare [| 2 .. 50 |]

Die Ausgabe lautet wie folgt.

Found an element: 1
Found an element: 729

Verwenden Sie Array.tryPick, wenn Sie zusätzlich zum Auffinden ein Element transformieren müssen. Das Ergebnis ist das erste Element, für das die Funktion das transformierte Element als Optionswert zurückgibt, oder None, wenn kein solches Element gefunden wird.

Im folgenden Code wird die Verwendung von Array.tryPick veranschaulicht: In diesem Fall werden statt eines Lambda-Ausdrucks mehrere lokale Hilfsfunktionen definiert, um den Code zu vereinfachen.

let findPerfectSquareAndCube array1 =
    let delta = 1.0e-10
    let isPerfectSquare (x:int) =
        let y = sqrt (float x)
        abs(y - round y) < delta
    let isPerfectCube (x:int) =
        let y = System.Math.Pow(float x, 1.0/3.0)
        abs(y - round y) < delta
    // intFunction : (float -> float) -> int -> int
    // Allows the use of a floating point function with integers.
    let intFunction function1 number = int (round (function1 (float number)))
    let cubeRoot x = System.Math.Pow(x, 1.0/3.0)
    // testElement: int -> (int * int * int) option
    // Test an element to see whether it is a perfect square and a perfect
    // cube, and, if so, return the element, square root, and cube root
    // as an option value. Otherwise, return None.
    let testElement elem = 
        if isPerfectSquare elem && isPerfectCube elem then
            Some(elem, intFunction sqrt elem, intFunction cubeRoot elem)
        else None
    match Array.tryPick testElement array1 with
    | Some (n, sqrt, cuberoot) -> printfn "Found an element %d with square root %d and cube root %d." n sqrt cuberoot
    | None -> printfn "Did not find an element that is both a perfect square and a perfect cube."

findPerfectSquareAndCube [| 1 .. 10 |]
findPerfectSquareAndCube [| 2 .. 100 |]
findPerfectSquareAndCube [| 100 .. 1000 |]
findPerfectSquareAndCube [| 1000 .. 10000 |]
findPerfectSquareAndCube [| 2 .. 50 |]

Die Ausgabe lautet wie folgt.

Found an element 1 with square root 1 and cube root 1.
Found an element 64 with square root 8 and cube root 4.
Found an element 729 with square root 27 and cube root 9.
Found an element 4096 with square root 64 and cube root 16.

Ausführen von Berechnungen für Arrays

Die Array.average-Funktion gibt den Durchschnitt jedes Elements in einem Array zurück. Sie ist auf Elementtypen beschränkt, die die exakte Division durch eine ganze Zahl unterstützen, wozu Gleitkommatypen aber keine ganzzahligen Typen gehören. Die Array.averageBy-Funktion gibt den Durchschnitt der Ergebnisse zurück, die eine Funktion für jedes Element aufrufen. Für ein Array eines ganzzahligen Typs können Sie Array.averageBy verwenden und für die Berechnung die Funktion jedes Element in einen Gleitkommatyp konvertieren lassen.

Verwenden Sie Array.max oder Array.min, um das maximale oder minimale Element abzurufen, wenn der Elementtyp dies unterstützt. Auf ähnliche Weise erlauben Array.maxBy und Array.minBy zunächst die Ausführung einer Funktion, ggf. zur Transformation eines Typs, der Vergleich unterstützt.

Array.sum fügt die Elemente eines Arrays hinzu, und Array.sumBy ruft für jedes Element eine Funktion auf und fügt die Ergebnisse zusammen.

Verwenden Sie Array.iter, um eine Funktion für jedes Element in einem Array auszuführen, ohne dabei die Rückgabewerte zu speichern. Verwenden Sie für eine Funktion mit zwei Arrays gleicher Länge Array.iter2. Wenn Sie auch ein Array mit Ergebnissen der Funktion anlegen möchten, verwenden Sie das Array.map- oder Array.map2-Element, die gleichzeitig auf zwei Arrays wirken.

Die Variationen Array.iteri und Array.iteri2 ermöglichen dem Index des Elements die Beteiligung an der Berechnung. Dasselbe gilt für Array.mapi und Array.mapi2.

Die Funktionen Array.fold, Array.foldBack, Array.reduce, Array.reduceBack, Array.scan und Array.scanBack führen Algorithmen aus, die alle Elemente eines Arrays einschließen. Auf ähnliche Weise führen die Variationen Array.fold2 und Array.foldBack2 Berechnungen für zwei Arrays aus.

Diese Funktionen zum Ausführen von Berechnungen entsprechen den Funktionen mit dem gleichen Namens im Listenmodul. Verwendungsbeispiele finden Sie unter Listen (F#).

Ändern von Arrays

Array.set legt ein Element auf einen angegebenen Wert fest. Array.fill legt einen Bereich von Elementen in einem Array auf einen angegebenen Wert fest. Das folgende Codebeispiel enthält ein Beispiel für Array.fill.

let arrayFill1 = [| 1 .. 25 |]
Array.fill arrayFill1 2 20 0
printfn "%A" arrayFill1

Die Ausgabe lautet wie folgt.

[|1; 2; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 23; 24; 25|]

Sie können mithilfe von Array.blit einen Unterabschnitt eines Arrays in ein anderes Array kopieren.

Konvertieren von Typen

Array.ofList erstellt ein Array aus einer Liste. Array.ofSeq erstellt ein Array aus einer Sequenz. Array.toList und Array.toSeq konvertieren vom Arraytyp in diese anderen Auflistungstypen.

Sortieren von Arrays

Verwenden Sie Array.sort, um mit der generischen Vergleichsfunktion ein Array zu sortieren. Verwenden Sie Array.sortBy, um eine Funktion anzugeben, die einen Wert mit der Bezeichnung Schlüssel generiert, um die generische Vergleichsfunktion auf den Schlüssel anzuwenden und so zu sortieren. Verwenden Sie Array.sortWith, wenn Sie eine benutzerdefinierte Vergleichsfunktion bereitstellen möchten. Array.sort, Array.sortBy und Array.sortWith geben das sortierte Array als neues Array zurück. Die Variationen Array.sortInPlace, Array.sortInPlaceBy und Array.sortInPlaceWith, um das vorhandene Array zu ändern, anstatt ein neues zurückzugeben.

Arrays und Tupel

Die Funktionen Array.zip und Array.unzip konvertieren Arrays von Tupelpaaren in Tupel von Arrays und umgekehrt. Array.zip3 und Array.unzip3 sind ähnlich, außer dass sie mit Tupeln von drei Elementen oder Tupeln von drei Arrays arbeiten.

Parallele Berechnungen auf Arrays

Das Modul Array.Parallel enthält Funktionen zum Ausführen paralleler Berechnungen für Arrays. Dieses Modul ist in Anwendungen nicht verfügbar, die auf Versionen vor Version 4 von .NET Framework abzielen.

Siehe auch

Weitere Ressourcen

F#-Sprachreferenz

F#-Typen