F# 배열

F# 배열 (Arrays)

F# 배열은 고정 크기(fixed-size)이고 0부터 시작하며(0-based), 수정 가능한(mutable) 연속 데이터 요소 모음이에요. 모든 요소는 반드시 같은 타입이어야 해요. 배열은 R#의 기본 컬렉션 중 하나라서 반복 작업, 검색, 계산 등에서 정말 자주 등장하는데요, 이번 글에서 배열을 만들고 접근하고 다루는 방법을 하나씩 살펴볼게요.

출처: https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/arrays

본문

배열 만들기 (Create arrays)

배열을 만드는 방법은 여러 가지가 있어요. 가장 간단한 방법은 [||] 사이에 세미콜론으로 구분된 연속 값을 나열하는 거예요. 다음 예시를 볼게요.

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

각 요소를 줄바꿈해서 별도의 줄에 적을 수도 있는데, 이 경우에는 세미콜론 구분자를 생략할 수 있어요.

let array1 =
    [|
        1
        2
        3
     |]

배열 요소의 타입은 사용된 리터럴(literal)로부터 추론(infer)되며, 모두 일관되어야 해요.

// This is an array of 3 integers.
let array1 = [| 1; 2; 3 |]
// This is an array of a tuple of 3 integers.
let array2 = [| 1, 2, 3 |]

다음 코드는 3.0이 float이고 12는 정수라서 오류가 발생해요.

// Causes an error. The 3.0 (float) cannot be converted to integer implicitly.
// let array3 = [| 1; 2; 3.0 |]

다음 코드도 1,2가 튜플이고 3이 정수라서 오류가 발생해요.

// Causes an error too. The 3 (integer) cannot be converted to tuple implicitly.
// let array4 = [| 1, 2; 3 |]

시퀀스 식(sequence expression)을 사용해서 배열을 만들 수도 있어요. 아래는 1부터 10까지 정수의 제곱으로 이루어진 배열을 만드는 예시예요.

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

모든 요소가 0으로 초기화된 배열을 만들려면 Array.zeroCreate를 사용해요.

let arrayOfTenZeroes : int array = Array.zeroCreate 10

요소 접근하기 (Access elements)

대괄호([])를 사용해서 배열 요소에 접근할 수 있어요. 예전의 점 표기법(.[index])도 여전히 지원되지만, F# 6.0부터는 권장되지 않아요.

array1[0]

배열 인덱스는 0부터 시작해요.

슬라이스 표기법(slice notation)을 사용해서 배열 요소에 접근할 수도 있는데, 이 방식을 쓰면 배열의 부분 범위(subrange)를 지정할 수 있어요. 슬라이스 표기법의 예시를 볼게요.

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

슬라이스 표기법을 사용하면 배열의 새로운 복사본이 만들어져요.

배열 타입과 모듈 (Array types and modules)

모든 F# 배열의 타입은 .NET Framework의 System.Array 타입이에요. 따라서 F# 배열은 System.Array에서 제공하는 모든 기능을 사용할 수 있어요.

Array 모듈은 1차원 배열에 대한 연산을 지원해요. Array2D, Array3D, Array4D 모듈에는 각각 2차원, 3차원, 4차원 배열에 대한 연산 함수가 들어 있어요. 4보다 큰 차원(rank)의 배열이 필요하다면 System.Array를 사용해서 만들 수 있어요.

기본 함수 (Simple functions)

Array.get은 요소를 가져오고, Array.length는 배열의 길이를 반환하며, Array.set은 특정 요소를 지정한 값으로 설정해요. 다음 예시가 이 함수들의 사용법을 보여줘요.

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)

출력 결과는 다음과 같아요.

0 1 2 3 4 5 6 7 8 9

배열을 만드는 함수 (Functions that create arrays)

기존 배열 없이 새 배열을 만드는 함수도 여러 개 있어요. Array.empty는 요소가 하나도 없는 새 배열을 만들어요. Array.create는 지정한 크기의 배열을 만들고 모든 요소를 주어진 값으로 설정해요. Array.init는 차원(dimension)과 요소를 생성할 함수를 받아 배열을 만들어요. Array.zeroCreate는 모든 요소가 해당 타입의 0 값으로 초기화된 배열을 만들어요. 다음 코드가 이 함수들을 보여줘요.

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

출력 결과는 다음과 같아요.

Length of empty array: 0
Array 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는 기존 배열에서 요소를 복사한 새 배열을 만들어요. 이 복사는 **얕은 복사(shallow copy)**라는 점에 주의해야 해요. 즉 요소 타입이 참조 타입(reference type)이라면 기본 객체가 아니라 참조만 복사된다는 뜻이에요. 다음 예시가 이를 보여줘요.

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

위 코드의 출력 결과는 다음과 같아요.

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

문자열 Test1은 첫 번째 배열에만 나타나요. 새 요소를 만드는 연산이 firstArray의 참조를 덮어쓰지만, secondArray에 여전히 존재하는 빈 문자열에 대한 원래 참조에는 영향을 주지 않기 때문이에요. 문자열 Test2는 두 배열 모두에 나타나는데, System.Text.StringBuilder 타입에 대한 Insert 연산이 두 배열이 모두 참조하는 기본 System.Text.StringBuilder 객체에 영향을 주기 때문이에요.

Array.sub는 배열의 부분 범위에서 새 배열을 만들어요. 시작 인덱스와 길이를 지정해서 부분 범위를 정해요. 다음 코드가 Array.sub의 사용법을 보여줘요.

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

출력은 부분 배열이 요소 5에서 시작하고 10개의 요소를 포함한다는 것을 보여줘요.

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

Array.append는 두 개의 기존 배열을 결합해서 새 배열을 만들어요.

다음 코드가 Array.append를 보여줘요.

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

위 코드의 출력 결과는 다음과 같아요.

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

Array.choose는 배열의 요소 중 새 배열에 포함할 요소를 골라내요. 다음 코드가 Array.choose를 보여줘요. 배열의 요소 타입이 option 타입으로 반환되는 값의 타입과 일치할 필요는 없다는 점에 주목해요. 이 예시에서 요소 타입은 int이고, option은 다항 함수 elem*elem - 1의 결과(부동 소수점 수)예요.

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

위 코드의 출력 결과는 다음과 같아요.

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

Array.collect는 기존 배열의 각 요소에 지정한 함수를 실행한 뒤, 함수가 생성한 요소들을 모아 하나의 새 배열로 결합해요. 다음 코드가 Array.collect를 보여줘요.

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

위 코드의 출력 결과는 다음과 같아요.

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

Array.concat는 배열들의 시퀀스(sequence)를 받아 하나의 배열로 결합해요. 다음 코드가 Array.concat을 보여줘요.

Array.concat [ [|0..3|] ; [|4|] ]
//output [|0; 1; 2; 3; 4|]

Array.concat [| [|0..3|] ; [|4|] |]
//output [|0; 1; 2; 3; 4|]

Array.filter는 Boolean 조건 함수를 받아, 입력 배열에서 조건이 true인 요소만 담은 새 배열을 만들어요. 다음 코드가 Array.filter를 보여줘요.

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

위 코드의 출력 결과는 다음과 같아요.

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

Array.rev는 기존 배열의 순서를 뒤집어 새 배열을 만들어요. 다음 코드가 Array.rev를 보여줘요.

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

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

위 코드의 출력 결과는 다음과 같아요.

"Hello world!"

파이프라인 연산자(|>)를 사용하면 배열을 변환하는 배열 모듈의 함수들을 쉽게 이어 붙일 수 있어요. 다음 예시를 볼게요.

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

출력은 다음과 같아요.

[|100; 36; 16; 4|]

다차원 배열 (Multidimensional arrays)

다차원 배열을 만들 수는 있지만, 다차원 배열 리터럴을 직접 쓰는 문법은 없어요. array2D 연산자를 사용해서 배열 요소의 시퀀스들의 시퀀스로부터 배열을 만들어요. 그 시퀀스들은 배열 리터럴이나 리스트 리터럴일 수 있어요. 예를 들어 다음 코드는 2차원 배열을 만들어요.

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

Array2D.init 함수를 사용해서 2차원 배열을 초기화할 수도 있고, 3차원·4차원 배열용으로 비슷한 함수도 있어요. 이 함수들은 요소를 만드는 데 사용할 함수를 받아요. 함수를 지정하는 대신 특정 초기값으로 채워진 2차원 배열을 만들려면 Array2D.create 함수를 사용해요. 이 함수는 4차원까지의 배열에도 사용할 수 있어요. 다음 예시는 먼저 원하는 요소를 담은 배열들의 배열(배열의 배열)을 만든 뒤, Array2D.init을 사용해 원하는 2차원 배열을 생성하는 방법을 보여줘요.

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

배열 인덱싱과 슬라이싱 문법은 차원(rank) 4까지의 배열에서 지원돼요. 여러 차원에서 인덱스를 지정할 때는 쉼표로 인덱스를 구분해요. 다음 예시가 이를 보여줘요.

twoDimensionalArray[0, 1] <- 1.0

2차원 배열의 타입은 [,]로 표기해요 (예: int[,], double[,]). 3차원 배열의 타입은 [,,]로 표기하고, 더 높은 차원의 배열도 이런 식으로 이어져요.

1차원 배열에 사용할 수 있는 함수 중 일부만 다차원 배열에서도 사용할 수 있어요.

배열 슬라이싱과 다차원 배열 (Array slicing and multidimensional arrays)

2차원 배열(행렬, matrix)에서는 범위를 지정하고 와일드카드(*) 문자를 사용해 전체 행이나 열을 지정해서 부분 행렬(sub-matrix)을 추출할 수 있어요.

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

다차원 배열을 같은 차원 또는 더 낮은 차원의 부분 배열로 분해할 수도 있어요. 예를 들어 단일 행이나 열을 지정해서 행렬에서 벡터(vector)를 얻을 수 있어요.

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

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

요소 접근 연산자와 오버로드된 GetSlice 메서드를 구현하는 타입이면 이 슬라이싱 문법을 사용할 수 있어요. 예를 들어 다음 코드는 F# 2차원 배열을 감싸는 Matrix 타입을 만들고, 배열 인덱싱을 지원하도록 Item 프로퍼티를 구현하며, GetSlice의 세 가지 버전을 구현해요. 이 코드를 행렬 타입의 템플릿으로 활용하면 이 절에서 설명하는 모든 슬라이싱 연산을 사용할 수 있어요.

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 $"{submatrix}"

    let firstRow = test1[0,*]
    let secondRow = test1[1,*]
    let firstCol = test1[*,0]
    printfn $"{firstCol}"

배열의 불리언(참/거짓) 함수 (Boolean functions on arrays)

Array.existsArray.exists2 함수는 각각 하나 또는 두 개의 배열에서 요소를 검사해요. 이 함수들은 테스트 함수를 받아서, 조건을 만족하는 요소가 (각각의 배열에서, Array.exists2의 경우 요소 쌍이) 존재하면 true를 반환해요.

다음 코드가 Array.existsArray.exists2의 사용법을 보여줘요. 이 예시들에서는 인자 중 하나, 여기서는 함수 인자만 적용해서 새 함수를 만들어요.

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

위 코드의 출력 결과는 다음과 같아요.

true
false
false
true

마찬가지로 Array.forall 함수는 배열의 모든 요소가 Boolean 조건을 만족하는지 검사해요. Array.forall2는 같은 길이의 두 배열의 요소를 이용하는 Boolean 함수로 같은 일을 해요. 다음 코드가 이 함수들의 사용법을 보여줘요.

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

이 예시들의 출력 결과는 다음과 같아요.

false
true
true
false

배열 검색 (Search arrays)

Array.find는 Boolean 함수를 받아 함수가 true를 반환하는 첫 번째 요소를 반환해요. 조건을 만족하는 요소가 없으면 System.Collections.Generic.KeyNotFoundException을 발생시켜요. Array.findIndexArray.find와 비슷하지만, 요소 자체가 아니라 요소의 인덱스를 반환한다는 점만 달라요.

다음 코드는 Array.findArray.findIndex를 사용해서 완전제곱수(perfect square)이면서 완전세제곱수(perfect cube)인 수를 찾아요.

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

출력 결과는 다음과 같아요.

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

Array.tryFindArray.find와 비슷하지만, 그 결과가 option 타입이고 요소를 찾지 못하면 None을 반환해요. 배열에 일치하는 요소가 있을지 확실하지 않을 때는 Array.find 대신 Array.tryFind를 사용해야 해요. 마찬가지로 Array.tryFindIndexArray.findIndex와 비슷한데 option 타입을 반환값으로 사용해요. 요소를 찾지 못하면 option은 None이 돼요.

다음 코드가 Array.tryFind의 사용법을 보여줘요. 이 코드는 앞선 코드에 의존해요.

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

출력 결과는 다음과 같아요.

Found an element: 1
Found an element: 729
Failed to find a matching element.

요소를 찾는 것에 더해 요소를 변환해야 할 때는 Array.tryPick을 사용해요. 결과는 함수가 변환된 요소를 option 값으로 반환하는 첫 번째 요소이거나, 그런 요소가 없으면 None이에요.

다음 코드는 Array.tryPick의 사용법을 보여줘요. 이 경우 람다 식 대신 코드를 단순하게 만들기 위해 여러 개의 로컬 헬퍼 함수(local helper function)가 정의돼 있어요.

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

출력 결과는 다음과 같아요.

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.
Did not find an element that is both a perfect square and a perfect cube.

배열에서 계산 수행하기 (Perform computations on arrays)

Array.average 함수는 배열의 각 요소의 평균을 반환해요. 이 함수는 정수로 정확히 나눗셈을 지원하는 요소 타입으로 제한되는데, 여기에는 부동 소수점 타입이 포함되고 정수 타입은 포함되지 않아요. Array.averageBy 함수는 각 요소에 함수를 호출한 결과의 평균을 반환해요. 정수 타입의 배열에서는 Array.averageBy를 사용하고, 함수가 각 요소를 계산을 위해 부동 소수점 타입으로 변환하도록 하면 돼요.

요소 타입이 지원한다면 Array.maxArray.min으로 최댓값 또는 최솟값을 얻을 수 있어요. 마찬가지로 Array.maxByArray.minBy는 먼저 함수를 실행해서, 아마도 비교를 지원하는 타입으로 변환하도록 할 수 있어요.

Array.sum은 배열의 요소를 더하고, Array.sumBy는 각 요소에 함수를 호출한 뒤 그 결과를 다 더해요.

반환값을 저장하지 않고 배열의 각 요소에 함수를 실행하려면 Array.iter를 사용해요. 같은 길이의 두 배열을 다루는 함수라면 Array.iter2를 사용해요. 함수의 결과 배열도 함께 유지해야 한다면 Array.map이나, 한 번에 두 배열을 다루는 Array.map2를 사용해요.

Array.iteriArray.iteri2는 요소의 인덱스를 계산에 포함시킬 수 있어요. Array.mapiArray.mapi2도 마찬가지예요.

Array.fold, Array.foldBack, Array.reduce, Array.reduceBack, Array.scan, Array.scanBack 함수는 배열의 모든 요소를 다루는 알고리즘을 실행해요. 마찬가지로 Array.fold2Array.foldBack2는 두 배열에 대해 계산을 수행해요.

이 계산 함수들은 List 모듈의 같은 이름의 함수들과 대응돼요. 사용 예시는 Lists 문서를 참고해요.

배열 수정하기 (Modify arrays)

Array.set은 요소를 지정한 값으로 설정해요. Array.fill은 배열의 요소 범위를 지정한 값으로 설정해요. 다음 코드는 Array.fill의 예시예요.

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

출력 결과는 다음과 같아요.

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

Array.blit을 사용하면 한 배열의 일부를 다른 배열로 복사할 수 있어요.

다른 타입으로 변환하기 (Convert to and from other types)

Array.ofList는 리스트로부터 배열을 만들어요. Array.ofSeq는 시퀀스로부터 배열을 만들어요. Array.toListArray.toSeq는 배열에서 이 다른 컬렉션 타입들로 변환해요.

배열 정렬하기 (Sort arrays)

Array.sort는 제네릭 비교 함수(generic comparison)를 사용해 배열을 정렬해요. Array.sortBy는 키(key)라고 부르는 값을 생성하는 함수를 지정해서, 그 키에 제네릭 비교 함수를 적용해 정렬해요. 사용자 지정 비교 함수를 제공하고 싶다면 Array.sortWith를 사용해요. Array.sort, Array.sortBy, Array.sortWith는 모두 정렬된 배열을 새 배열로 반환해요. Array.sortInPlace, Array.sortInPlaceBy, Array.sortInPlaceWith는 새 배열을 반환하는 대신 기존 배열을 수정해요.

배열과 튜플 (Arrays and tuples)

Array.zipArray.unzip 함수는 튜플 쌍의 배열을 배열들의 튜플로, 또는 그 반대로 변환해요. Array.zip3Array.unzip3은 3개 요소의 튜플 또는 3개 배열의 튜플을 다룬다는 점만 빼고 비슷해요.

배열의 병렬 계산 (Parallel computations on arrays)

Array.Parallel 모듈에는 배열에서 병렬 계산을 수행하는 함수들이 들어 있어요. 이 모듈은 .NET Framework 4 이전 버전을 대상으로 하는 애플리케이션에서는 사용할 수 없어요.

더 알아보기 (Learn more)