Share via


Segmentos

En este artículo se explica cómo tomar segmentos de tipos de F# existentes y cómo definir segmentos propios.

En F#, un segmento es un subconjunto de cualquier tipo de datos. Los segmentos son similares a los indizadores, pero en lugar de producir un único valor de la estructura de datos subyacente, producen varios. Los segmentos usan la sintaxis del operador .. para seleccionar el rango de índices especificados de un tipo de datos. Para obtener más información, vea el artículo de referencia de la expresión de bucle.

Actualmente, F# tiene compatibilidad intrínseca con las cadenas, las listas, las matrices y las matrices multidimensionales (2D, 3D, 4D) de segmentación. La segmentación se usa con más frecuencia con matrices y listas de F#. Puede agregar segmentación a los tipos de datos personalizados mediante el método GetSlice de la definición de tipo o en una extensión de tipo en el ámbito.

Segmentación de listas y matrices de F#

Los tipos de datos más comunes que se segmentan son listas y matrices de F#. En el siguiente ejemplo se muestra como segmentar listas:

// Generate a list of 100 integers
let fullList = [ 1 .. 100 ]

// Create a slice from indices 1-5 (inclusive)
let smallSlice = fullList[1..5]
printfn $"Small slice: {smallSlice}"

// Create a slice from the beginning to index 5 (inclusive)
let unboundedBeginning = fullList[..5]
printfn $"Unbounded beginning slice: {unboundedBeginning}"

// Create a slice from an index to the end of the list
let unboundedEnd = fullList[94..]
printfn $"Unbounded end slice: {unboundedEnd}"

La segmentación de matrices es igual a la de listas:

// Generate an array of 100 integers
let fullArray = [| 1 .. 100 |]

// Create a slice from indices 1-5 (inclusive)
let smallSlice = fullArray[1..5]
printfn $"Small slice: {smallSlice}"

// Create a slice from the beginning to index 5 (inclusive)
let unboundedBeginning = fullArray[..5]
printfn $"Unbounded beginning slice: {unboundedBeginning}"

// Create a slice from an index to the end of the list
let unboundedEnd = fullArray[94..]
printfn $"Unbounded end slice: {unboundedEnd}"

Antes de F# 6, la segmentación usaba la sintaxis expr.[start..finish] con el . adicional. Si así lo quiere, puede seguir usando esta sintaxis. Para obtener más información, vea RFC FS-1110.

Segmentación de matrices multidimensionales

F# admite matrices multidimensionales de la biblioteca principal de F#. Al igual que las matrices unidimensionales, los segmentos de matrices multidimensionales también pueden ser útiles. Pero la incorporación de dimensiones adicionales exige una sintaxis ligeramente diferente para poder tomar segmentos de filas y columnas específicas.

Los ejemplos siguientes muestran cómo segmentar una matriz 2D:

// Generate a 3x3 2D matrix
let A = array2D [[1;2;3];[4;5;6];[7;8;9]]
printfn $"Full matrix:\n {A}"

// Take the first row
let row0 = A[0,*]
printfn $"{row0}"

// Take the first column
let col0 = A[*,0]
printfn $"{col0}"

// Take all rows but only two columns
let subA = A[*,0..1]
printfn $"{subA}"

// Take two rows and all columns
let subA' = A[0..1,*]
printfn $"{subA}"

// Slice a 2x2 matrix out of the full 3x3 matrix
let twoByTwo = A[0..1,0..1]
printfn $"{twoByTwo}"

Definición de segmentos para otras estructuras de datos

La biblioteca principal de F# define segmentos para un conjunto limitado de tipos. Si quiere definir segmentos para más tipos de datos, puede hacerlo en la propia definición de tipo o en una extensión de tipo.

Por ejemplo, así se pueden definir segmentos para la clase ArraySegment<T> a fin de permitir una manipulación de datos cómoda:

open System

type ArraySegment<'TItem> with
    member segment.GetSlice(start, finish) =
        let start = defaultArg start 0
        let finish = defaultArg finish segment.Count
        ArraySegment(segment.Array, segment.Offset + start, finish - start)

let arr = ArraySegment [| 1 .. 10 |]
let slice = arr[2..5] //[ 3; 4; 5]

Otro ejemplo con los tipos Span<T> y ReadOnlySpan<T>:

open System

type ReadOnlySpan<'T> with
    member sp.GetSlice(startIdx, endIdx) =
        let s = defaultArg startIdx 0
        let e = defaultArg endIdx sp.Length
        sp.Slice(s, e - s)

type Span<'T> with
    member sp.GetSlice(startIdx, endIdx) =
        let s = defaultArg startIdx 0
        let e = defaultArg endIdx sp.Length
        sp.Slice(s, e - s)

let printSpan (sp: Span<int>) =
    let arr = sp.ToArray()
    printfn $"{arr}"

let sp = [| 1; 2; 3; 4; 5 |].AsSpan()
printSpan sp[0..] // [|1; 2; 3; 4; 5|]
printSpan sp[..5] // [|1; 2; 3; 4; 5|]
printSpan sp[0..3] // [|1; 2; 3|]
printSpan sp[1..3] // |2; 3|]

Los segmentos de F# integrados son inclusivos del final

Todos los segmentos intrínsecos de F# son inclusivos del final, es decir, el límite superior se incluye en el segmento. En un segmento determinado con índice x inicial e índice y final, el segmento resultante incluye el valor .

// Define a new list
let xs = [1 .. 10]

printfn $"{xs[2..5]}" // Includes the 5th index

Segmentos vacíos de F# integrados

Las listas, matrices, secuencias, cadenas y matrices multidimensionales (2D, 3D, 4D) de F# generan un segmento vacío si la sintaxis puede producir un segmento que no existe.

Considere el ejemplo siguiente:

let l = [ 1..10 ]
let a = [| 1..10 |]
let s = "hello!"

let emptyList = l[-2..(-1)]
let emptyArray = a[-2..(-1)]
let emptyString = s[-2..(-1)]

Importante

Los desarrolladores de C# pueden esperar que inicien una excepción en lugar de generar un segmento vacío. Se trata de una decisión de diseño basada en el hecho de que las colecciones vacías se componen en F#. Una lista de F# vacía se puede componer con otra lista de F#, una cadena vacía se puede agregar a una cadena existente, etc. Puede ser habitual tomar segmentos en función de los valores pasados como parámetros, y ser tolerante con los > fuera de los límites mediante la generación de una colección vacía se ajusta a la naturaleza de composición del código de F#.

Segmentos de índice fijo para matrices 3D y 4D

En el caso de las matrices 3D y 4D de F#, puede "corregir" un índice determinado y segmentar otras dimensiones con ese índice fijo.

Para ilustrarlo, considere la siguiente matriz 3D:

z = 0

x\y 0 1
0 0 1
1 2 3

z = 1

x\y 0 1
0 4 5
1 6 7

Si quiere extraer el segmento [| 4; 5 |] de la matriz, use un segmento de índice fijo.

let dim = 2
let m = Array3D.zeroCreate<int> dim dim dim

let mutable count = 0

for z in 0..dim-1 do
    for y in 0..dim-1 do
        for x in 0..dim-1 do
            m[x,y,z] <- count
            count <- count + 1

// Now let's get the [4;5] slice!
m[*, 0, 1]

La última línea corrige los índices y y z de la matriz 3D y toma el resto de los valores x que corresponden a la matriz.

Consulte también