Sdílet prostřednictvím


Pole (F#)

Pole mají pevnou velikost, založenou na nule, proměnlivé kolekce po sobě následujících datových elementů, které jsou všechny stejného typu.

Tvorba polí

Pole lze vytvořit několika způsoby.Malé pole můžete vytvořit uvedením po sobě následujících hodnot mezi [| a |] a oddělením středníkem, jak je znázorněno v následujících příkladech.

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

Každý element můžete také umístit na samostatný řádek, ve kterémžto případě je volitelný oddělovač středník.

let array1 = 
    [|
        1
        2
        3
     |]

Typ prvků pole je odvozen z použitých literál a musí být jednotný.Následující kód způsobí chybu, protože 1.0 je typu "float" a 2 a 3 jsou celá čísla.

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

Sekvence výrazů můžete také použít k vytvoření polí.Následuje příklad, který vytvoří pole druhých mocnin celých čísel od 1 do 10.

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

K vytvoření pole, ve kterém jsou všechny elementy inicializovány na nulu, použijte Array.zeroCreate.

let arrayOfTenZeroes : int array = Array.zeroCreate 10

Přístup k prvkům

Můžete přistupovat k prvkům pole pomocí operátoru tečka (.) a hranaté závorky ([a]).

array1.[0]

Indexy pole začínají od 0.

K prvkům pole se dostanete pomocí zápisu řezu, který umožňuje určit dílčí řadu pole.Příklady postupu zápisu řezu.

// 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..] 

Při použití zápisu řezu je vytvořena nový kopie pole.

Typy polí a moduly

Typ všech polí F# je typ .NET Framework Array.Proto pole F# podporují všechny funkce, které jsou k dispozici v Array.

Modul knihovny Microsoft.FSharp.Collections.Array podporuje operace pro jednorozměrné pole.Moduly Array2D, Array3D a Array4D obsahují funkce, které podporují operace pro pole dvou, tří a čtyř dimenzí (v uvedeném pořadí).Můžete vytvářet pole většího zařazení než čtyři pomocí Array.

Jednoduché funkce

Array.get získá element.Array.length udává délku pole.Array.set nastaví element na zadanou hodnotu.Následující příklad kódu ukazuje použití těchto funkcí.

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)

Výstup je následující.

0 1 2 3 4 5 6 7 8 9

Funkce, které vytvářejí pole

Několik funkcí tvoří pole bez nutnosti existujícího pole.Array.empty vytvoří nové pole, které neobsahuje žádné prvky.Array.create vytvoří pole určené velikosti a nastaví všechny prvky na zadané hodnoty.Array.Init vytvoří pole s danou dimenzí a funkce pro generování prvků.Array.zeroCreate vytvoří pole, ve kterém jsou všechny prvky inicializovány na nulovou hodnotu pro typ pole.Následující kód demonstruje tyto funkce.

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

Výstup je následující.

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 vytvoří nové pole obsahující prvky, které jsou zkopírovány z existujícího pole.Všimněte si, že kopie je mělká, což znamená, že pokud typ elementu je typem odkazu, bude zkopírován pouze odkaz, nikoli základní objekt.Následující příklad kódu to dokládá.

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

Výstup předcházejícího kódu vypadá takto:

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

Řetězec Test1 se zobrazuje jenom v prvním poli, protože operace vytvoření nového elementu přepíše odkaz v firstArray, ale nemá vliv na původní odkaz na prázdný řetězec, který je stále přítomen v secondArray.Řetězec Test2 se zobrazuje v obou polích, protože operace Insert v typu StringBuilder ovlivňuje základní objekt StringBuilder, který je odkazován v obou polích.

Array.sub generuje nové pole z podrozsahu pole.Zadejte dílčí sadu poskytnutím počáteční index a délky.Následující kód demonstruje použití Array.sub.

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

Výstup ukazuje, že podpole začíná prvkem 5 a obsahuje 10 prvků.

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

Array.append vytvoří nové pole kombinací dvou existujících polí.

Následující kód znázorňuje Array.append.

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

Výstup předcházejícího kódu vypadá takto.

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

Array.choose vybere prvky pole pro zahrnutí do nového pole.Následující kód znázorňuje Array.choose.Všimněte si, že typ prvku v poli nemusí odpovídat typu hodnoty vrácené v typu možnosti.V tomto příkladu je typ prvku int a možnost je výsledek polynomické funkce elem*elem - 1 jako číslo s plovoucí desetinnou čárkou.

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

Výstup předcházejícího kódu vypadá takto.

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

Array.collect spustí určenou funkci na každém elementu pole existujícího pole a poté shromáždí elementy generované funkcí a zkombinuje je do nového pole.Následující kód znázorňuje Array.collect.

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

Výstup předcházejícího kódu vypadá takto.

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

Array.concat přebírá pořadí polí a kombinuje je do jediného pole.Následující kód znázorňuje 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))

Výstup předcházejícího kódu vypadá takto.

[|(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 převezme logickou podmínku funkce a generuje nové pole, které obsahuje pouze elementy z vstupního pole, pro které je podmínka pravdivá.Následující kód znázorňuje Array.filter.

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

Výstup předcházejícího kódu vypadá takto.

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

Array.rev generuje nové pole přehozením pořadí existujícího pole.Následující kód znázorňuje Array.rev.

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

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

Výstup předcházejícího kódu vypadá takto.

"Hello world!"

Můžete snadno kombinovat funkce v modulu pole, které transformují pole pomocí operátoru kanálu (|>), jak je znázorněno v následujícím příkladu.

[| 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"

Výstup je

[|100; 36; 16; 4|]

Vícerozměrná pole

Vícedimenzionální pole mohou být vytvořena, ale neexistuje žádná syntaxe zápisu vícedimenzionálního literálu pole.Použijte operátor array2D pro vytvoření pole ze sekvence sekvencí elementů pole.Sekvence může být pole nebo literály seznamu.Například následující kód vytvoří dvourozměrné pole.

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

Můžete také použít funkci Array2D.init k inicializaci pole dvou dimenzí a podobné funkce jsou k dispozici pro pole se třemi až čtyřmi dimenzemi.Tyto funkce přebírají funkci, která slouží k vytváření elementů.Pokud chcete vytvořit dvojrozměrné pole obsahující elementy nastavené na počáteční hodnotu místo určení funkce, použijte funkci Array2D.create, která je k dispozici také pro pole až do čtyř dimenzí.Následující příklad kódu nejprve ukazuje, jak vytvořit pole obsahující požadované prvky a potom použije Array2D.init k vytvoření požadovaného dvourozměrného pole.

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

Pole indexování a plátkování syntaxe jsou podporovány pro pole do pořadí 4.Při zadávání indexu ve více dimenzích používáte čárky k oddělení indexů, jak je znázorněno v následujícím příkladu kódu.

twoDimensionalArray.[0, 1] <- 1.0

Typ dvourozměrného pole je zapsán jako <type>[,] (například int[,], double[,]), a typ trojrozměrného pole je zapsán jako <type>[,,] atd. pro pole vyšších rozměrů.

Pouze dílčí sada funkcí, které jsou k dispozici pro jednorozměrné pole, je také k dispozici pro vícedimenzionální pole.Další informace naleznete v tématu Collections.Array – modul (F#), Collections.Array2D – modul (F#), Collections.Array3D – modul (F#) a Collections.Array4D – modul (F#).

Řezání pole a vícedimenzionální pole

Dvourozměrné pole (matice) může extrahovat dílčí matici určením rozsahů a pomocí zástupného znaku (*) a zadáním celého řádku nebo sloupce.

// Get rows 1 to N from an NxM matrix (returns a matrix):
matrix.[1.., *]

// Get rows 1 to 3 from a matrix (returns a matrix):
matrix.[1..3, *]

// Get columns 1 to 3 from a matrix (returns a matrix):
matrix.[*, 1..3]

// Get a 3x3 submatrix:
matrix.[1..3, 1..3]

Stejně jako v případě F# 3.1 můžete rozložit vícerozměrné pole na podpole stejné nebo nižší dimenze.Vektor lze získat například z matice zadáním jednoho řádku nebo sloupce.

// Get row 3 from a matrix as a vector:
matrix.[3, *]

// Get column 3 from a matrix as a vector:
matrix.[*, 3]

Tuto syntaxi dělení můžete použít u typů, které implementují operátory přístupu k elementu a metody přetížení GetSlice.Například následující kód vytvoří typ matice, který obtéká pole F# 2D, implementuje vlastnost položky pro poskytnutí podporu pro indexování pole a implementuje tři verze GetSlice.Pokud tento kód můžete použít jako šablonu pro vaše typy matice, můžete použít všechny operace řezů, které tento oddíl popisuje.

type Matrix<'T>(N: int, M: int) =
    let internalArray = Array2D.zeroCreate<'T> N M

    member this.Item
        with get(a: int, b: int) = internalArray.[a, b]
        and set(a: int, b: int) (value:'T) = internalArray.[a, b] <- value

    member this.GetSlice(rowStart: int option, rowFinish : int option,
                         colStart: int option, colFinish : int option) =
           let rowStart = match rowStart with
                          | Some(v) -> v
                          | None -> 0
           let rowFinish = match rowFinish with
                           | Some(v) -> v
                           | None -> internalArray.GetLength(0) - 1
           let colStart = match colStart with
                          | Some(v) -> v
                          | None -> 0
           let colFinish = match colFinish with
                           | Some(v) -> v
                           | None -> internalArray.GetLength(1) - 1
           internalArray.[rowStart..rowFinish, colStart..colFinish]

    member this.GetSlice(row: int, colStart: int option, colFinish: int option) =
           let colStart = match colStart with
                          | Some(v) -> v
                          | None -> 0
           let colFinish = match colFinish with
                           | Some(v) -> v
                           | None -> internalArray.GetLength(1) - 1
           internalArray.[row, colStart..colFinish]

    member this.GetSlice(rowStart: int option, rowFinish: int option, col: int) =
           let rowStart = match rowStart with
                          | Some(v) -> v
                          | None -> 0
           let rowFinish = match rowFinish with
                           | Some(v) -> v
                           | None -> internalArray.GetLength(0) - 1
           internalArray.[rowStart..rowFinish, col]

module test =

    let generateTestMatrix x y =
        let matrix = new Matrix<float>(3, 3);
        for i in 0..2 do
           for j in 0..2 do
               matrix.[i, j] <- float(i) * x - float(j) * y
        matrix

    let test1 = generateTestMatrix 2.3 1.1
    let submatrix = test1.[0..1, 0..1]
    printfn "%A" submatrix

    let firstRow = test1.[0,*]
    let secondRow = test1.[1,*]
    let firstCol = test1.[*,0]
    printfn "%A" firstCol

Logické funkce pro pole

Funkce Array.exists a Array.exists2 testuje prvky v jednou nebo ve dvou polích.Tyto funkce provádějí funkci testu a vrátí true, pokud existuje element (nebo dvojice elementů pro Array.exists2), splňující danou podmínku.

Následující kód demonstruje použití Array.exists a Array.exists2.V těchto příkladech jsou nové funkce vytvořeny použitím pouze jednoho z argumentů, v těchto případech argumentem funkce.

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|])

Výstup předcházejícího kódu vypadá takto.

true
false
false
true

Podobně funkce Array.forall testuje pole a určuje, zda každý prvek splňuje logickou podmínku.Variace Array.forall2 provede stejnou akci pomocí logické funkce, která zahrnuje elementy dvou polí stejné délky.Následující kód ukazuje použití těchto funkcí.

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 |])

Výstup pro tyto příklady je tento.

false
true
true
false

Pole hledání

Array.find přebírá logickou funkci a vrátí první prvek, pro který vrátí funkce hodnotu true nebo vyvolá KeyNotFoundException v případě, že není nalezen žádný element, který splňuje podmínku.Array.findIndex je jako Array.find, s tím rozdílem, že vrátí index elementu namísto samotného elementu.

Následující kód používá Array.find a Array.findIndex k vyhledání čísla, které je dokonalý čtverec i dokonalá krychle.

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

Výstup je následující.

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

Array.tryFind je jako Array.find, s tím rozdílem, že výsledek je typ možnosti a vrátí None, pokud není nalezen žádný element.Array.tryFind by měla být použita místo Array.find když si nejste jisti zda je odpovídající prvek v poli.Podobně Array.tryFindIndex je jako Array.findIndex s tím rozdílem, že typ možnosti je vrácenou hodnotou.Pokud není nalezen žádný element, možnost je None.

Následující kód demonstruje použití Array.tryFind.Tento kód závisí na předchozím kódu.

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 |]

Výstup je následující.

Found an element: 1
Found an element: 729

Použijte Array.tryPick, pokud potřebujete transformovat element kromě vyhledání.Výsledkem je první prvek, pro který funkce vrátí transformovaný prvek jako hodnotu možnosti, nebo None, pokud žádný takový prvek není nalezen.

Následující kód ukazuje použití Array.tryPick.V tomto případě namísto výrazu lambda je definováno několik místních pomocných funkcí pro zjednodušení kódu.

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 |]

Výstup je následující.

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.

Provádění výpočtů v polích

Funkce Array.average vrátí průměr z jednotlivých prvků v poli.Je omezena na typy prvků, které podporují přesné dělení celým číslem, které zahrnuje typy plovoucího bodu, ale ne integrální typy.Funkce Array.averageBy vrátí průměr z výsledků volání funkce u každého prvku.Pro pole integrálního typu můžete použít Array.averageBy a nechat funkce převést každý prvek na typ plovoucí desetinné čárky pro výpočet.

Použijte Array.max nebo Array.min, chcete-li získat maximální nebo minimální element, pokud to typ elementu podporuje.Podobně Array.maxBy a Array.minBy umožňuje přednostní spuštění funkce, např. pro převod na typ, který podporuje porovnání.

Array.sum přidává prvky pole a Array.sumBy volá funkci na každý element a přidá výsledky dohromady.

Chcete-li spustit funkci v každém elementu v poli bez uložení vrácených hodnot, použijte Array.iter.Pro funkci zahrnující dvě pole stejné délky, použijte Array.iter2.Pokud potřebujete zachovat pole výsledků této funkce, použijte Array.map nebo Array.map2, jež pracuje současně na dvou polích.

Variace Array.iteri a Array.iteri2 umožňuje zahrnutí indexu elementu do výpočtu. To stejné platí pro Array.mapi a Array.mapi2.

Funkce Array.fold, Array.foldBack, Array.reduce, Array.reduceBack, Array.scan a Array.scanBack spouští algoritmy, které se týkají všech prvků pole.Podobně variace Array.fold2 a Array.foldBack2 provádí výpočty na dvou polích.

Tyto funkce k provádění výpočtů odpovídají funkcím se stejným názvem v modulu seznamu.Příklady využití naleznete v tématu Seznamy (F#).

Změna polí

Array.set nastaví element na zadanou hodnotu.Array.fill nastaví rozsah elementů v matici na zadanou hodnotu.Následující kód obsahuje příklad Array.fill.

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

Výstup je následující.

[|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|]

Můžete použít soubor Array.blit ke kopírování dílčí sady jednoho pole do jiného pole.

Převedení do a z ostatních typů

Array.ofList vytvoří pole ze seznamu.Array.ofSeq vytvoří pole ze sekvence.Array.toList a Array.toSeq převede tyto typy kolekcí z typu pole.

Pole třídění

Použijte Array.sort, chcete-li seřadit pole pomocí funkce obecného porovnání.Použijte Array.sortBy k zadání funkce, která generuje hodnotu označovanou jako klíč, k uspořádání pomocí funkce obecného porovnání v klíči.Použijte Array.sortWith, pokud chcete poskytnout vlastní funkci porovnání.Array.sort, Array.sortBy i Array.sortWith vrátí seřazené pole jako nové pole.Variace Array.sortInPlace, Array.sortInPlaceBy a Array.sortInPlaceWith mění stávající pole místo vrácení nového.

Pole a n-tice

Funkce Array.zip a Array.unzip převádí pole párů n-tic na n-tice polí a naopak.Array.zip3 a Array.unzip3 jsou podobné s tím rozdílem, že pracují s n-ticemi tří prvků nebo n-ticemi tří polí.

Paralelní výpočty v polích

Modul Array.Parallel obsahuje funkce pro provádění paralelních výpočtů v polích.Tento modul není k dispozici v aplikacích, které mají cílové verze rozhraní .NET Framework starší než verze 4.

Viz také

Další zdroje

Referenční dokumentace jazyka F#

Typy F#