Secuencias

Una secuencia es una serie lógica de elementos de un tipo. Las secuencias son especialmente útiles cuando tiene una colección grande y ordenada de datos, pero no necesariamente espera usar todos los elementos. Los elementos de secuencia individuales solo se calculan según sea necesario, por lo que una secuencia puede proporcionar un mejor rendimiento que una lista en situaciones en las que no se usan todos los elementos. Las secuencias se representan mediante seq<'T> el tipo , que es un alias para IEnumerable<T> . Por lo tanto, cualquier tipo de .NET que IEnumerable<T> implemente la interfaz se puede usar como secuencia. El módulo Seq proporciona compatibilidad con manipulaciones que implican secuencias.

Expresiones de secuencia

Una expresión de secuencia es una expresión que se evalúa como una secuencia. Las expresiones de secuencia pueden tener varias formas. La forma más sencilla especifica un intervalo. Por ejemplo, crea una secuencia que contiene cinco elementos, incluidos los extremos seq { 1 .. 5 } 1 y 5. También puede especificar un incremento (o decremento) entre dos períodos dobles. Por ejemplo, el código siguiente crea la secuencia de múltiplo de 10.

// Sequence that has an increment.
seq { 0 .. 10 .. 100 }

Las expresiones de secuencia se resumen en expresiones de F# que generan valores de la secuencia. También puede generar valores mediante programación:

seq { for i in 1 .. 10 -> i * i }

En el ejemplo anterior se usa el operador , que permite especificar -> una expresión cuyo valor pasará a formar parte de la secuencia. Solo se puede usar -> si cada parte del código siguiente devuelve un valor.

Como alternativa, puede especificar la palabra do clave , con un opcional que yield sigue:

seq { for i in 1 .. 10 do yield i * i }

// The 'yield' is implicit and doesn't need to be specified in most cases.
seq { for i in 1 .. 10 do i * i }

El código siguiente genera una lista de pares de coordenadas junto con un índice en una matriz que representa la cuadrícula. Tenga en cuenta que for la primera expresión requiere que se especifique do .

let (height, width) = (10, 10)

seq {
    for row in 0 .. width - 1 do
        for col in 0 .. height - 1 ->
            (row, col, row*width + col)
    }

Una if expresión utilizada en una secuencia es un filtro. Por ejemplo, para generar una secuencia de solo números primos, suponiendo que tiene una función de tipo , construya la isprime secuencia como se muestra a int -> bool continuación.

seq { for n in 1 .. 100 do if isprime n then n }

Como se mencionó anteriormente, do aquí es necesario porque no hay ninguna rama que vaya con else if . Si intenta usar , verá un error que dice que no todas -> las ramas devuelven un valor.

La palabra clave yield!.

A veces, es posible que desee incluir una secuencia de elementos en otra secuencia. Para incluir una secuencia dentro de otra secuencia, deberá usar la palabra yield! clave :

// Repeats '1 2 3 4 5' ten times
seq {
    for _ in 1..10 do
        yield! seq { 1; 2; 3; 4; 5}
}

Otra manera de pensar en es que aplana una secuencia interna y, a continuación, la yield! incluye en la secuencia que lo contiene.

Cuando yield! se usa en una expresión, todos los demás valores únicos deben usar la palabra clave yield :

// Combine repeated values with their values
seq {
    for x in 1..10 do
        yield x
        yield! seq { for i in 1..x -> i}
}

En el ejemplo anterior se producirá el valor x de además de todos los valores de a para cada 1 x x .

Ejemplos

En el primer ejemplo se usa una expresión de secuencia que contiene una iteración, un filtro y un rendimiento para generar una matriz. Este código imprime una secuencia de números primos entre 1 y 100 en la consola.

// Recursive isprime function.
let isprime n =
    let rec check i =
        i > n/2 || (n % i <> 0 && check (i + 1))
    check 2

let aSequence =
    seq {
        for n in 1..100 do
            if isprime n then
                n
    }

for x in aSequence do
    printfn "%d" x

En el ejemplo siguiente se crea una tabla de multiplicación que consta de tuplas de tres elementos, cada uno de los que consta de dos factores y el producto:

let multiplicationTable =
    seq {
        for i in 1..9 do
            for j in 1..9 ->
                (i, j, i*j)
    }

En el ejemplo siguiente se muestra el uso de yield! para combinar secuencias individuales en una única secuencia final. En este caso, las secuencias de cada subárbol de un árbol binario se concatenan en una función recursiva para generar la secuencia final.

// Yield the values of a binary tree in a sequence.
type Tree<'a> =
   | Tree of 'a * Tree<'a> * Tree<'a>
   | Leaf of 'a

// inorder : Tree<'a> -> seq<'a>
let rec inorder tree =
    seq {
      match tree with
          | Tree(x, left, right) ->
               yield! inorder left
               yield x
               yield! inorder right
          | Leaf x -> yield x
    }

let mytree = Tree(6, Tree(2, Leaf(1), Leaf(3)), Leaf(9))
let seq1 = inorder mytree
printfn "%A" seq1

Utilizar secuencias

Las secuencias admiten muchas de las mismas funciones que las listas. Las secuencias también admiten operaciones como la agrupación y el recuento mediante funciones de generación de claves. Las secuencias también admiten funciones más diversas para extraer subsecuencias.

Muchos tipos de datos, como listas, matrices, conjuntos y mapas, son secuencias implícitamente porque son colecciones enumerables. Una función que toma una secuencia como argumento funciona con cualquiera de los tipos de datos de F# comunes, además de cualquier tipo de datos .NET que implemente System.Collections.Generic.IEnumerable<'T> . Compare esto con una función que toma una lista como argumento, que solo puede tomar listas. El tipo seq<'T> es una abreviatura de tipo para IEnumerable<'T> . Esto significa que cualquier tipo que implemente el genérico , que incluye matrices, listas, conjuntos y mapas en F#, y también la mayoría de los tipos de colección de .NET, es compatible con el tipo y se puede usar siempre que se espera una System.Collections.Generic.IEnumerable<'T> seq secuencia.

Funciones del módulo

El módulo Seq del espacio de nombres FSharp.Collections contiene funciones para trabajar con secuencias. Estas funciones también funcionan con listas, matrices, mapas y conjuntos, ya que todos esos tipos son enumerables y, por tanto, se pueden tratar como secuencias.

Crear secuencias

Puede crear secuencias mediante expresiones de secuencia, como se ha descrito anteriormente, o mediante determinadas funciones.

Puede crear una secuencia vacía mediante Seq.emptyo puede crear una secuencia de solo un elemento especificado mediante Seq.singleton.

let seqEmpty = Seq.empty
let seqOne = Seq.singleton 10

Puede usar Seq.init para crear una secuencia para la que se crean los elementos mediante una función que proporcione. También se proporciona un tamaño para la secuencia. Esta función es igual que List.init, salvo que los elementos no se crean hasta que se recorre en iteración la secuencia. En el código siguiente, se muestra el uso de Seq.init.

let seqFirst5MultiplesOf10 = Seq.init 5 (fun n -> n * 10)
Seq.iter (fun elem -> printf "%d " elem) seqFirst5MultiplesOf10

El resultado es

0 10 20 30 40

Con Seq.ofArray y Seq.ofList< no> Function , puede crear secuencias a partir de matrices y listas. Sin embargo, también puede convertir matrices y listas en secuencias mediante un operador de conversión. Ambas técnicas se muestran en el código siguiente.

// Convert an array to a sequence by using a cast.
let seqFromArray1 = [| 1 .. 10 |] :> seq<int>

// Convert an array to a sequence by using Seq.ofArray.
let seqFromArray2 = [| 1 .. 10 |] |> Seq.ofArray

Mediante seq.cast, puede crear una secuencia a partir de una colección débilmente con tipo, como las definidas en System.Collections . Estas colecciones con tipos débiles tienen el tipo de elemento System.Object y se enumeran mediante el tipo no System.Collections.Generic.IEnumerable&#96;1 genérico. En el código siguiente se muestra el uso de Seq.cast para convertir un objeto en una System.Collections.ArrayList secuencia.

open System

let arr = ResizeArray<int>(10)

for i in 1 .. 10 do
    arr.Add(10)

let seqCast = Seq.cast arr

Puede definir secuencias infinitas mediante la función Seq.initInfinite. Para este tipo de secuencia, se proporciona una función que genera cada elemento a partir del índice del elemento. Las secuencias infinitas son posibles debido a la evaluación diferida; Los elementos se crean según sea necesario llamando a la función que especifique. En el ejemplo de código siguiente se genera una secuencia infinita de números de punto flotante, en este caso la serie alterna de recíprocos de cuadrados de enteros sucesivos.

let seqInfinite =
    Seq.initInfinite (fun index ->
        let n = float (index + 1)
        1.0 / (n * n * (if ((index + 1) % 2 = 0) then 1.0 else -1.0)))

printfn "%A" seqInfinite

Seq.unfold genera una secuencia a partir de una función de cálculo que toma un estado y la transforma para generar cada elemento posterior de la secuencia. El estado es simplemente un valor que se usa para calcular cada elemento y puede cambiar a medida que se calcula cada elemento. El segundo argumento de Seq.unfold es el valor inicial que se usa para iniciar la secuencia. Seq.unfold usa un tipo de opción para el estado , que permite finalizar la secuencia devolviendo el None valor . En el código siguiente se muestran dos ejemplos de secuencias, seq1 y fib , generadas por una operación unfold . La primera, seq1 , es simplemente una secuencia simple con números de hasta 20. El segundo, fib , usa para calcular la secuencia de unfold Fibonacci. Dado que cada elemento de la secuencia de Fibonacci es la suma de los dos números de Fibonacci anteriores, el valor de estado es una tupla que consta de los dos números anteriores de la secuencia. El valor inicial es (1,1) , los dos primeros números de la secuencia.

let seq1 =
    0 // Initial state
    |> Seq.unfold (fun state ->
        if (state > 20) then
            None
        else
            Some(state, state + 1))

printfn "The sequence seq1 contains numbers from 0 to 20."

for x in seq1 do
    printf "%d " x

let fib =
    (1, 1) // Initial state
    |> Seq.unfold (fun state ->
        if (snd state > 1000) then
            None
        else
            Some(fst state + snd state, (snd state, fst state + snd state)))

printfn "\nThe sequence fib contains Fibonacci numbers."
for x in fib do printf "%d " x

La salida es como sigue:

The sequence seq1 contains numbers from 0 to 20.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

The sequence fib contains Fibonacci numbers.

2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

El código siguiente es un ejemplo que usa muchas de las funciones del módulo de secuencia descritas aquí para generar y calcular los valores de secuencias infinitas. El código puede tardar unos minutos en ejecutarse.

// generateInfiniteSequence generates sequences of floating point
// numbers. The sequences generated are computed from the fDenominator
// function, which has the type (int -> float) and computes the
// denominator of each term in the sequence from the index of that
// term. The isAlternating parameter is true if the sequence has
// alternating signs.
let generateInfiniteSequence fDenominator isAlternating =
    if (isAlternating) then
        Seq.initInfinite (fun index ->
            1.0 /(fDenominator index) * (if (index % 2 = 0) then -1.0 else 1.0))
    else
        Seq.initInfinite (fun index -> 1.0 /(fDenominator index))

// The harmonic alternating series is like the harmonic series
// except that it has alternating signs.
let harmonicAlternatingSeries = generateInfiniteSequence (fun index -> float index) true

// This is the series of reciprocals of the odd numbers.
let oddNumberSeries = generateInfiniteSequence (fun index -> float (2 * index - 1)) true

// This is the series of recipocals of the squares.
let squaresSeries = generateInfiniteSequence (fun index -> float (index * index)) false

// This function sums a sequence, up to the specified number of terms.
let sumSeq length sequence =
    (0, 0.0)
    |>
    Seq.unfold (fun state ->
        let subtotal = snd state + Seq.item (fst state + 1) sequence
        if (fst state >= length) then
            None
        else
            Some(subtotal, (fst state + 1, subtotal)))

// This function sums an infinite sequence up to a given value
// for the difference (epsilon) between subsequent terms,
// up to a maximum number of terms, whichever is reached first.
let infiniteSum infiniteSeq epsilon maxIteration =
    infiniteSeq
    |> sumSeq maxIteration
    |> Seq.pairwise
    |> Seq.takeWhile (fun elem -> abs (snd elem - fst elem) > epsilon)
    |> List.ofSeq
    |> List.rev
    |> List.head
    |> snd

// Compute the sums for three sequences that converge, and compare
// the sums to the expected theoretical values.
let result1 = infiniteSum harmonicAlternatingSeries 0.00001 100000
printfn "Result: %f  ln2: %f" result1 (log 2.0)

let pi = Math.PI
let result2 = infiniteSum oddNumberSeries 0.00001 10000
printfn "Result: %f pi/4: %f" result2 (pi/4.0)

// Because this is not an alternating series, a much smaller epsilon
// value and more terms are needed to obtain an accurate result.
let result3 = infiniteSum squaresSeries 0.0000001 1000000
printfn "Result: %f pi*pi/6: %f" result3 (pi*pi/6.0)

Buscar y buscar elementos

Las secuencias admiten la funcionalidad disponible con listas: Seq.exists, Seq.exists2, Seq.find, Seq.findIndex, Seq.pick, Seq.tryFind y Seq.tryFindIndex. Las versiones de estas funciones que están disponibles para las secuencias evalúan la secuencia solo hasta el elemento que se está buscando. Para obtener ejemplos, vea Listas.

Obtención de subsecuencias

Seq.filter y Seq.choose son como las funciones correspondientes que están disponibles para las listas, salvo que el filtrado y la selección no se producen hasta que se evalúan los elementos de secuencia.

Seq.truncate crea una secuencia a partir de otra secuencia, pero limita la secuencia a un número especificado de elementos. Seq.take crea una nueva secuencia que contiene solo un número especificado de elementos desde el inicio de una secuencia. Si hay menos elementos en la secuencia de los que se especifican para tomar, Seq.take produce una System.InvalidOperationException excepción . La diferencia entre y es que no genera un error si el número de elementos es Seq.take menor que el número Seq.truncate Seq.truncate especificado.

El código siguiente muestra el comportamiento de y las diferencias entre Seq.truncate y Seq.take .

let mySeq = seq { for i in 1 .. 10 -> i*i }
let truncatedSeq = Seq.truncate 5 mySeq
let takenSeq = Seq.take 5 mySeq

let truncatedSeq2 = Seq.truncate 20 mySeq
let takenSeq2 = Seq.take 20 mySeq

let printSeq seq1 = Seq.iter (printf "%A ") seq1; printfn ""

// Up to this point, the sequences are not evaluated.
// The following code causes the sequences to be evaluated.
truncatedSeq |> printSeq
truncatedSeq2 |> printSeq
takenSeq |> printSeq
// The following line produces a run-time error (in printSeq):
takenSeq2 |> printSeq

La salida, antes de que se produzca el error, es la siguiente.

1 4 9 16 25
1 4 9 16 25 36 49 64 81 100
1 4 9 16 25
1 4 9 16 25 36 49 64 81 100

Mediante Seq.takeWhile, puede especificar una función de predicado (una función booleana) y crear una secuencia a partir de otra secuencia que se conste de esos elementos de la secuencia original para la que el predicado es , pero detenerse antes del primer elemento para el que el true predicado devuelve false . Seq.skip devuelve una secuencia que omite un número especificado de los primeros elementos de otra secuencia y devuelve los elementos restantes. Seq.skipWhile devuelve una secuencia que omite los primeros elementos de otra secuencia siempre que el predicado devuelva y, a continuación, devuelve los elementos restantes, empezando por el primer elemento para el que el true predicado devuelve false .

En el ejemplo de código siguiente se muestra el comportamiento de y las diferencias entre Seq.takeWhile Seq.skip , y Seq.skipWhile .

// takeWhile
let mySeqLessThan10 = Seq.takeWhile (fun elem -> elem < 10) mySeq
mySeqLessThan10 |> printSeq

// skip
let mySeqSkipFirst5 = Seq.skip 5 mySeq
mySeqSkipFirst5 |> printSeq

// skipWhile
let mySeqSkipWhileLessThan10 = Seq.skipWhile (fun elem -> elem < 10) mySeq
mySeqSkipWhileLessThan10 |> printSeq

La salida es la siguiente.

1 4 9
36 49 64 81 100
16 25 36 49 64 81 100

Transformar secuencias

Seq.pairwise crea una nueva secuencia en la que los elementos sucesivos de la secuencia de entrada se agrupan en tuplas.

let printSeq seq1 = Seq.iter (printf "%A ") seq1; printfn ""
let seqPairwise = Seq.pairwise (seq { for i in 1 .. 10 -> i*i })
printSeq seqPairwise

printfn ""
let seqDelta = Seq.map (fun elem -> snd elem - fst elem) seqPairwise
printSeq seqDelta

Seq.windowed es como , salvo que, en lugar de generar una secuencia de tuplas, genera una secuencia de matrices que contienen copias de elementos Seq.pairwise adyacentes (una ventana) de la secuencia. Especifique el número de elementos adyacentes que desea en cada matriz.

En el siguiente ejemplo de código se muestra el uso de Seq.windowed. En este caso, el número de elementos de la ventana es 3. En el ejemplo se printSeq usa , que se define en el ejemplo de código anterior.

let seqNumbers = [ 1.0; 1.5; 2.0; 1.5; 1.0; 1.5 ] :> seq<float>
let seqWindows = Seq.windowed 3 seqNumbers
let seqMovingAverage = Seq.map Array.average seqWindows
printfn "Initial sequence: "
printSeq seqNumbers
printfn "\nWindows of length 3: "
printSeq seqWindows
printfn "\nMoving average: "
printSeq seqMovingAverage

La salida es la siguiente.

Secuencia inicial:

1.0 1.5 2.0 1.5 1.0 1.5

Windows of length 3:
[|1.0; 1.5; 2.0|] [|1.5; 2.0; 1.5|] [|2.0; 1.5; 1.0|] [|1.5; 1.0; 1.5|]

Moving average:
1.5 1.666666667 1.5 1.333333333

Operaciones con varias secuencias

Seq.zip y Seq.zip3 toman dos o tres secuencias y generan una secuencia de tuplas. Estas funciones son similares a las funciones correspondientes disponibles para las listas. No hay ninguna funcionalidad correspondiente para separar una secuencia en dos o más secuencias. Si necesita esta funcionalidad para una secuencia, convierta la secuencia en una lista y use List.unzip.

Ordenación, comparación y agrupación

Las funciones de ordenación admitidas para las listas también funcionan con secuencias. Esto incluye Seq.sort y Seq.sortBy. Estas funciones recorren en iteración toda la secuencia.

Se comparan dos secuencias mediante la función Seq.compareWith. La función compara los elementos sucesivos a su vez y se detiene cuando encuentra el primer par desigual. Los elementos adicionales no contribuyen a la comparación.

En el código siguiente se muestra el uso de Seq.compareWith.

let sequence1 = seq { 1 .. 10 }
let sequence2 = seq { 10 .. -1 .. 1 }

// Compare two sequences element by element.
let compareSequences =
    Seq.compareWith (fun elem1 elem2 ->
        if elem1 > elem2 then 1
        elif elem1 < elem2 then -1
        else 0)

let compareResult1 = compareSequences sequence1 sequence2
match compareResult1 with
| 1 -> printfn "Sequence1 is greater than sequence2."
| -1 -> printfn "Sequence1 is less than sequence2."
| 0 -> printfn "Sequence1 is equal to sequence2."
| _ -> failwith("Invalid comparison result.")

En el código anterior, solo se calcula y examina el primer elemento y el resultado es -1.

Seq.countBy toma una función que genera un valor denominado clave para cada elemento. Se genera una clave para cada elemento llamando a esta función en cada elemento. Seq.countBy a continuación, devuelve una secuencia que contiene los valores de clave y un recuento del número de elementos que generaron cada valor de la clave.

let mySeq1 = seq { 1.. 100 }

let printSeq seq1 = Seq.iter (printf "%A ") seq1

let seqResult =
    mySeq1
    |> Seq.countBy (fun elem ->
        if elem % 3 = 0 then 0
        elif elem % 3 = 1 then 1
        else 2)

printSeq seqResult

La salida es la siguiente.

(1, 34) (2, 33) (0, 33)

La salida anterior muestra que hubo 34 elementos de la secuencia original que generaron la clave 1, 33 valores que generaron la clave 2 y 33 valores que generaron la clave 0.

Puede agrupar elementos de una secuencia llamando a Seq.groupBy. Seq.groupBy toma una secuencia y una función que genera una clave a partir de un elemento . La función se ejecuta en cada elemento de la secuencia. Seq.groupBy devuelve una secuencia de tuplas, donde el primer elemento de cada tupla es la clave y el segundo es una secuencia de elementos que generan esa clave.

En el ejemplo de código siguiente se muestra el uso de para particionar la secuencia de números de 1 a 100 en tres grupos que tienen los valores de clave Seq.groupBy distintos 0, 1 y 2.

let sequence = seq { 1 .. 100 }

let printSeq seq1 = Seq.iter (printf "%A ") seq1

let sequences3 =
    sequences
    |> Seq.groupBy (fun index ->
        if (index % 3 = 0) then 0
        elif (index % 3 = 1) then 1
        else 2)

sequences3 |> printSeq

La salida es la siguiente.

(1, seq [1; 4; 7; 10; ...]) (2, seq [2; 5; 8; 11; ...]) (0, seq [3; 6; 9; 12; ...])

Puede crear una secuencia que elimine los elementos duplicados llamando a Seq.distinct. O bien, puede usar Seq.distinctBy, que toma una función que genera claves para que se llame a en cada elemento. La secuencia resultante contiene elementos de la secuencia original que tienen claves únicas; Se descartan los elementos posteriores que producen una clave duplicada en un elemento anterior.

En el siguiente ejemplo de código, se muestra el uso de Seq.distinct. Seq.distinct se muestra generando secuencias que representan números binarios y, a continuación, mostrando que los únicos elementos distintos son 0 y 1.

let binary n =
    let rec generateBinary n =
        if (n / 2 = 0) then [n]
        else (n % 2) :: generateBinary (n / 2)

    generateBinary n
    |> List.rev
    |> Seq.ofList

printfn "%A" (binary 1024)

let resultSequence = Seq.distinct (binary 1024)
printfn "%A" resultSequence

El código siguiente muestra empezando por una secuencia que contiene números negativos y positivos y usando la función de valor absoluto como Seq.distinctBy función generadora de claves. A la secuencia resultante le faltan todos los números positivos que corresponden a los números negativos de la secuencia, porque los números negativos aparecen anteriormente en la secuencia y, por tanto, se seleccionan en lugar de los números positivos que tienen el mismo valor absoluto o clave.

let inputSequence = { -5 .. 10 }
let printSeq seq1 = Seq.iter (printf "%A ") seq1

printfn "Original sequence: "
printSeq inputSequence

printfn "\nSequence with distinct absolute values: "
let seqDistinctAbsoluteValue = Seq.distinctBy (fun elem -> abs elem) inputSequence
printSeq seqDistinctAbsoluteValue

Secuencias de solo lectura y almacenadas en caché

Seq.readonly crea una copia de solo lectura de una secuencia. Seq.readonly es útil cuando tiene una colección de lectura y escritura, como una matriz, y no desea modificar la colección original. Esta función se puede usar para conservar la encapsulación de datos. En el ejemplo de código siguiente, se crea un tipo que contiene una matriz. Una propiedad expone la matriz, pero en lugar de devolver una matriz, devuelve una secuencia que se crea a partir de la matriz mediante Seq.readonly .

type ArrayContainer(start, finish) =
    let internalArray = [| start .. finish |]
    member this.RangeSeq = Seq.readonly internalArray
    member this.RangeArray = internalArray

let newArray = new ArrayContainer(1, 10)
let rangeSeq = newArray.RangeSeq
let rangeArray = newArray.RangeArray

// These lines produce an error:
//let myArray = rangeSeq :> int array
//myArray[0] <- 0

// The following line does not produce an error.
// It does not preserve encapsulation.
rangeArray[0] <- 0

Seq.cache crea una versión almacenada de una secuencia. Use Seq.cache para evitar la reevaluación de una secuencia o cuando tenga varios subprocesos que usen una secuencia, pero debe asegurarse de que cada elemento se actúa una sola vez. Cuando tiene una secuencia que usan varios subprocesos, puede tener un subproceso que enumera y calcula los valores de la secuencia original, y los subprocesos restantes pueden usar la secuencia almacenada en caché.

Realizar cálculos en secuencias

Las operaciones aritméticas simples son como las de las listas, como Seq.average, Seq.sum, Seq.averageBy, Seq.sumBy,y así sucesivamente.

Seq.fold, Seq.reducey Seq.scan son como las funciones correspondientes que están disponibles para las listas. Las secuencias admiten un subconjunto de las variaciones completa de estas funciones que enumera la compatibilidad. Para obtener más información y ejemplos, vea Enumerar.

Vea también