Listas

En F#, una lista es una serie ordenada e inmutable de elementos del mismo tipo. Para realizar operaciones básicas en listas, use las funciones del módulo List.

Crear e inicializar listas

Para definir una lista, puede enumerar explícitamente los elementos, separados por punto y coma y escritos entre corchetes, tal y como se muestra en la línea de código siguiente.

let list123 = [ 1; 2; 3 ]

También puede insertar saltos de línea entre los elementos, en cuyo caso el signo de punto y coma es opcional. La última sintaxis produce un código más legible cuando las expresiones de inicialización de elementos son más largas o si quiere incluir un comentario para cada elemento.

let list123 = [ 1; 2; 3 ]

Normalmente, todos los elementos de lista deben ser del mismo tipo. Una excepción es que una lista en la cual los elementos se han especificado para que sean de un tipo base puede tener elementos que sean de tipos derivados. Por lo tanto, lo siguiente es aceptable, porque tanto Button como CheckBox derivan de Control.

let myControlList: Control list = [ new Button(); new CheckBox() ]

También puede definir elementos de lista usando un intervalo indicado por enteros separados por el operador de intervalo (..), tal y como se muestra en el código siguiente.

let list1 = [ 1..10 ]

Una lista vacía se especifica por un par de corchetes con nada entre ellos.

// An empty list.
let listEmpty = []

También puede usar una expresión de secuencia para crear una lista. Vea Expresiones de secuenciapara obtener más información. Por ejemplo, el código siguiente crea una lista de cuadrados de enteros, de 1 a 10.

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

Operadores para trabajar con listas

Puede asociar elementos a una lista usando el operador :: (cons). Si list1 es [2; 3; 4], el código siguiente crea list2 como [100; 2; 3; 4].

let list2 = 100 :: list1

Para concatenar listas que tengan tipos compatibles, puede usar el operador @, como en el código siguiente. Si list1 es [2; 3; 4] y list2 es [100; 2; 3; 4], este código crea list3 como [2; 3; 4; 100; 2; 3; 4].

let list3 = list1 @ list2

Las funciones para realizar operaciones en las listas están disponibles en el módulo List.

Como en F# las listas son inmutables, las operaciones de modificación generan nuevas listas en lugar de modificar las existentes.

En F#, las listas se implementan como listas vinculadas individualmente, lo que significa que las operaciones que solo acceden al encabezado de la lista son O(1) y el acceso a los elementos es O(n).

Propiedades

El tipo de lista admite las siguientes propiedades:

Propiedad Tipo Descripción
Head 'T El primer elemento.
Vacía 'T list Propiedad estática que devuelve una lista vacía del tipo apropiado.
IsEmpty bool true si la lista no tiene ningún elemento.
Elemento 'T Elemento en el índice especificado (base cero).
Longitud int Número de elementos.
Tail 'T list La lista sin el primer elemento.

Los siguientes son algunos ejemplos de cómo usar estas propiedades.

let list1 = [ 1; 2; 3 ]

// Properties
printfn "list1.IsEmpty is %b" (list1.IsEmpty)
printfn "list1.Length is %d" (list1.Length)
printfn "list1.Head is %d" (list1.Head)
printfn "list1.Tail.Head is %d" (list1.Tail.Head)
printfn "list1.Tail.Tail.Head is %d" (list1.Tail.Tail.Head)
printfn "list1.Item(1) is %d" (list1.Item(1))

Usar listas

Programar con listas permite realizar operaciones complejas con una pequeña cantidad de código. En esta sección se describen las operaciones comunes en las listas que son importantes para la programación funcional.

Recursión con listas

Las listas están especialmente indicadas para las técnicas de programación recursiva. Tomemos una operación que deba realizarse en todos los elementos de una lista. Puede hacerlo recursivamente ejecutando una operación en el encabezado de la lista y, después, devolviendo la cola de la lista (que es una lista más pequeña formada por la lista original sin el primer elemento) de nuevo al siguiente nivel de recursión.

Para escribir una función recursiva de este estilo, se usa el operador cons (::) en coincidencia de patrones, lo que permite separar el encabezado de una lista de la cola.

En el ejemplo de código siguiente se muestra cómo usar la coincidencia de patrones para implementar una función recursiva que realice operaciones en una lista.

let rec sum list =
    match list with
    | head :: tail -> head + sum tail
    | [] -> 0

El código anterior funciona bien para listas pequeñas, pero en listas mayores podría desbordar la pila. El código siguiente mejora este código usando un argumento acumulador, una técnica estándar para trabajar con funciones recursivas. El uso del argumento acumulador hace que la función sea recursiva en la cola, lo que ahorra espacio en la pila.

let sum list =
    let rec loop list acc =
        match list with
        | head :: tail -> loop tail (acc + head)
        | [] -> acc

    loop list 0

La función RemoveAllMultiples es una función recursiva que toma dos listas. La primera lista contiene los números cuyos múltiplos se van a quitar, y la segunda es la lista de la que se van a quitar los números. El código del ejemplo siguiente usa esta función recursiva para eliminar de una lista todos los números que no sean primos, dejando como resultado una lista de números primos.

let IsPrimeMultipleTest n x = x = n || x % n <> 0

let rec RemoveAllMultiples listn listx =
    match listn with
    | head :: tail -> RemoveAllMultiples tail (List.filter (IsPrimeMultipleTest head) listx)
    | [] -> listx


let GetPrimesUpTo n =
    let max = int (sqrt (float n))
    RemoveAllMultiples [ 2..max ] [ 1..n ]

printfn "Primes Up To %d:\n %A" 100 (GetPrimesUpTo 100)

La salida es como sigue:

Primes Up To 100:
[2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37; 41; 43; 47; 53; 59; 61; 67; 71; 73; 79; 83; 89; 97]

Funciones del módulo

El módulo List proporciona funciones que acceden a los elementos de una lista. El elemento de encabezado es la manera más rápida y sencilla de acceder. Use la propiedad Head o la función del módulo List.head. Puede acceder a la cola de una lista usando la propiedad Tail o la función List.tail. Para buscar un elemento por índice, use la función List.nth. List.nth atraviesa la lista. Por lo tanto, es O(n). Si su código usa List.nth con frecuencia, quizás quiera considerar la posibilidad de usar una matriz en lugar de una lista. El acceso a elementos en las matrices es O(1).

Operaciones booleanas en listas

La función List.isEmpty determina si una lista tiene algún elemento.

La función List.exists aplica una prueba booleana a los elementos de una lista y devuelve true si algún elemento cumple la prueba. List.exists2 es similar pero funciona en pares sucesivos de elementos de dos listas.

En el código siguiente se muestra cómo usar List.exists.

// Use List.exists to determine whether there is an element of a list satisfies a given Boolean expression.
// containsNumber returns true if any of the elements of the supplied list match
// the supplied number.
let containsNumber number list = List.exists (fun elem -> elem = number) list
let list0to3 = [0 .. 3]
printfn "For list %A, contains zero is %b" list0to3 (containsNumber 0 list0to3)

La salida es como sigue:

For list [0; 1; 2; 3], contains zero is true

El siguiente ejemplo muestra el uso de List.exists2.

// Use List.exists2 to compare elements in two lists.
// isEqualElement returns true if any elements at the same position in two supplied
// lists match.
let isEqualElement list1 list2 = List.exists2 (fun elem1 elem2 -> elem1 = elem2) list1 list2
let list1to5 = [ 1 .. 5 ]
let list5to1 = [ 5 .. -1 .. 1 ]
if (isEqualElement list1to5 list5to1) then
    printfn "Lists %A and %A have at least one equal element at the same position." list1to5 list5to1
else
    printfn "Lists %A and %A do not have an equal element at the same position." list1to5 list5to1

La salida es como sigue:

Lists [1; 2; 3; 4; 5] and [5; 4; 3; 2; 1] have at least one equal element at the same position.

Puede usar List.forall si quiere probar si todos los elementos de una lista cumplen una condición.

let isAllZeroes list = List.forall (fun elem -> elem = 0.0) list
printfn "%b" (isAllZeroes [0.0; 0.0])
printfn "%b" (isAllZeroes [0.0; 1.0])

La salida es como sigue:

true
false

De forma similar, List.forall2 determina si todos los elementos en las posiciones correspondientes en dos listas satisfacen una expresión booleana que involucra cada par de elementos.

let listEqual list1 list2 = List.forall2 (fun elem1 elem2 -> elem1 = elem2) list1 list2
printfn "%b" (listEqual [0; 1; 2] [0; 1; 2])
printfn "%b" (listEqual [0; 0; 0] [0; 1; 0])

La salida es como sigue:

true
false

Operaciones de ordenación en listas

Las funciones List.sort, List.sortBy y List.sortWith ordenan las listas. La función de ordenación determina cuál de estas tres funciones se usará. List.sort usa una comparación genérica predeterminada. La comparación genérica usa operadores globales basados en la función de comparación genérica para comparar valores. Funciona de forma eficaz con una amplia variedad de tipos de elemento, como tipos numéricos simples, tuplas, registros, uniones discriminadas, listas, matrices y cualquier tipo que implemente System.IComparable. Para los tipos que implementan System.IComparable, la comparación genérica usa la función System.IComparable.CompareTo(). La comparación genérica también trabaja con cadenas, pero usa una ordenación independiente de la referencia cultural. La comparación genérica no se debe usar en tipos no admitidos, como los tipos de función. Además, el rendimiento de la comparación genérica predeterminada es mejor para tipos estructurados pequeños; para los tipos estructurados mayores que deben compararse y ordenarse con frecuencia, considere la posibilidad de implementar System.IComparable y de proporcionar una implementación eficaz del método System.IComparable.CompareTo().

List.sortBy toma una función que devuelve un valor que se usa como criterio de ordenación, y List.sortWith toma una función de comparación como argumento. Estas dos últimas funciones son útiles cuando se trabaja con tipos que no permiten la comparación, o cuando la comparación requiere semánticas de comparación más complejas, como es el caso de las cadenas que tienen en cuenta la referencia cultural.

El siguiente ejemplo muestra el uso de List.sort.

let sortedList1 = List.sort [1; 4; 8; -2; 5]
printfn "%A" sortedList1

La salida es como sigue:

[-2; 1; 4; 5; 8]

El siguiente ejemplo muestra el uso de List.sortBy.

let sortedList2 = List.sortBy (fun elem -> abs elem) [1; 4; 8; -2; 5]
printfn "%A" sortedList2

La salida es como sigue:

[1; -2; 4; 5; 8]

El siguiente ejemplo muestra el uso de List.sortWith. En este ejemplo, la función de comparación personalizada compareWidgets se usa para comparar primero un campo de un tipo personalizado, y después otro cuando los valores del primer campo son iguales.

type Widget = { ID: int; Rev: int }

let compareWidgets widget1 widget2 =
   if widget1.ID < widget2.ID then -1 else
   if widget1.ID > widget2.ID then 1 else
   if widget1.Rev < widget2.Rev then -1 else
   if widget1.Rev > widget2.Rev then 1 else
   0

let listToCompare = [
    { ID = 92; Rev = 1 }
    { ID = 110; Rev = 1 }
    { ID = 100; Rev = 5 }
    { ID = 100; Rev = 2 }
    { ID = 92; Rev = 1 }
    ]

let sortedWidgetList = List.sortWith compareWidgets listToCompare
printfn "%A" sortedWidgetList

La salida es como sigue:

[{ID = 92;
Rev = 1;}; {ID = 92;
Rev = 1;}; {ID = 100;
Rev = 2;}; {ID = 100;
Rev = 5;}; {ID = 110;
Rev = 1;}]

Operaciones de búsqueda en listas

Se admiten numerosas operaciones de búsqueda en las listas. La más simple, List.find, permite buscar el primer elemento que coincide con una condición especificada.

El ejemplo de código siguiente muestra el uso de List.find para buscar el primer número que es divisible por 5 en una lista.

let isDivisibleBy number elem = elem % number = 0
let result = List.find (isDivisibleBy 5) [ 1 .. 100 ]
printfn "%d " result

El resultado es 5.

Si los elementos deben transformarse primero, llame a List.pick, que toma una función que devuelve una opción, y busca el primer valor de la opción que sea Some(x). En lugar de devolver el elemento, List.pick devuelve el resultado x. Si no se encuentra ningún elemento coincidente, List.pick activa System.Collections.Generic.KeyNotFoundException. En el código siguiente se muestra el uso de List.pick.

let valuesList = [ ("a", 1); ("b", 2); ("c", 3) ]

let resultPick = List.pick (fun elem ->
                    match elem with
                    | (value, 2) -> Some value
                    | _ -> None) valuesList
printfn "%A" resultPick

La salida es como sigue:

"b"

Otro grupo de operaciones de búsqueda, List.tryFind y las funciones relacionadas, devuelve un valor de opción. La función List.tryFind devuelve el primer elemento de una lista que cumple una condición si ese elemento existe, pero el valor de opción None si no. La variación List.tryFindIndex devuelve el índice del elemento si se encuentra, en lugar del propio elemento. Estas funciones quedan reflejadas en el código siguiente.

let list1d = [1; 3; 7; 9; 11; 13; 15; 19; 22; 29; 36]
let isEven x = x % 2 = 0
match List.tryFind isEven list1d with
| Some value -> printfn "The first even value is %d." value
| None -> printfn "There is no even value in the list."

match List.tryFindIndex isEven list1d with
| Some value -> printfn "The first even value is at position %d." value
| None -> printfn "There is no even value in the list."

La salida es como sigue:

The first even value is 22.
The first even value is at position 8.

Operaciones aritméticas en listas

Las operaciones aritméticas comunes, como la suma y el promedio, están integradas en el módulo List. Para trabajar con List.sum, el tipo de elemento de lista debe admitir el operador + y tener un valor de cero. Todos los tipos aritmético integrados cumplen estas condiciones. Para trabajar con List.average, el tipo de elemento debe admitir la división sin resto, lo que excluye los tipos enteros pero permite los tipos de punto flotante. Las funciones List.sumBy y List.averageBy toman una función como parámetro, y los resultados de esta función se usan para calcular los valores de la suma o el promedio.

En el código siguiente se muestra cómo usar List.sum, List.sumBy y List.average.

// Compute the sum of the first 10 integers by using List.sum.
let sum1 = List.sum [1 .. 10]

// Compute the sum of the squares of the elements of a list by using List.sumBy.
let sum2 = List.sumBy (fun elem -> elem*elem) [1 .. 10]

// Compute the average of the elements of a list by using List.average.
let avg1 = List.average [0.0; 1.0; 1.0; 2.0]

printfn "%f" avg1

La salida es 1.000000.

En el código siguiente se muestra el uso de List.averageBy.

let avg2 = List.averageBy (fun elem -> float elem) [1 .. 10]
printfn "%f" avg2

La salida es 5.5.

Listas y tuplas

Las listas que contienen tuplas se pueden manipular con las funciones zip y unzip. Estas funciones combinan dos listas de valores únicos en una lista de tuplas o separan una lista de tuplas en dos listas de valores únicos. La función List.zip más simple toma dos listas de elementos únicos y crea una sola lista de pares de tuplas. Otra versión, List.zip3, toma tres listas de elementos únicos y crea una sola lista de tuplas que tienen tres elementos. En el siguiente ejemplo de código se muestra el uso de List.zip.

let list1 = [ 1; 2; 3 ]
let list2 = [ -1; -2; -3 ]
let listZip = List.zip list1 list2
printfn "%A" listZip

La salida es como sigue:

[(1, -1); (2, -2); (3; -3)]

En el siguiente ejemplo de código se muestra el uso de List.zip3.

let list3 = [ 0; 0; 0]
let listZip3 = List.zip3 list1 list2 list3
printfn "%A" listZip3

La salida es como sigue:

[(1, -1, 0); (2, -2, 0); (3, -3, 0)]

Las versiones unzip correspondientes, List.unzip y List.unzip3, toman listas de tuplas y devuelven listas en una tupla; la primera lista contiene todos los elementos que iban primero en cada tupla, la segunda lista contiene el segundo elemento de cada tupla, etc.

En el siguiente ejemplo de código se muestra el uso de List.unzip.

let lists = List.unzip [(1,2); (3,4)]
printfn "%A" lists
printfn "%A %A" (fst lists) (snd lists)

La salida es como sigue:

([1; 3], [2; 4])
[1; 3] [2; 4]

En el siguiente ejemplo de código se muestra el uso de List.unzip3.

let listsUnzip3 = List.unzip3 [(1,2,3); (4,5,6)]
printfn "%A" listsUnzip3

La salida es como sigue:

([1; 4], [2; 5], [3; 6])

Operar en elementos de lista

F# admite diferentes operaciones en los elementos de lista. La más simple es List.iter, que permite llamar a una función en cada elemento de una lista. Algunas variaciones son List.iter2, que permite realizar una operación en elementos de dos listas, List.iteri, que es como List.iter excepto que el índice de cada elemento se pasa como un argumento a la función que se llama para cada elemento, y List.iteri2, que es una combinación de la funcionalidad de List.iter2 y List.iteri. En el siguiente ejemplo de código se muestran estas funciones.

let list1 = [1; 2; 3]
let list2 = [4; 5; 6]
List.iter (fun x -> printfn "List.iter: element is %d" x) list1
List.iteri(fun i x -> printfn "List.iteri: element %d is %d" i x) list1
List.iter2 (fun x y -> printfn "List.iter2: elements are %d %d" x y) list1 list2
List.iteri2 (fun i x y ->
                printfn "List.iteri2: element %d of list1 is %d element %d of list2 is %d"
                  i x i y)
            list1 list2

La salida es como sigue:

List.iter: element is 1
List.iter: element is 2
List.iter: element is 3
List.iteri: element 0 is 1
List.iteri: element 1 is 2
List.iteri: element 2 is 3
List.iter2: elements are 1 4
List.iter2: elements are 2 5
List.iter2: elements are 3 6
List.iteri2: element 0 of list1 is 1; element 0 of list2 is 4
List.iteri2: element 1 of list1 is 2; element 1 of list2 is 5
List.iteri2: element 2 of list1 is 3; element 2 of list2 is 6

Otra función que se usa con frecuencia y que transforma elementos de lista es List.map, que permite aplicar una función a cada elemento de una lista y colocar todos los resultados en una lista nueva. List.map2 y List.map3 son variaciones que toman varias listas. También puede usar List.mapi y List.mapi2 si, además del elemento, se debe pasar a la función el índice de cada elemento. La única diferencia entre List.mapi2 y List.mapi es que List.mapi2 trabaja con dos listas. En el ejemplo siguiente se muestra List.map.

let list1 = [1; 2; 3]
let newList = List.map (fun x -> x + 1) list1
printfn "%A" newList

La salida es como sigue:

[2; 3; 4]

En el siguiente ejemplo se muestra el uso de List.map2.

let list1 = [1; 2; 3]
let list2 = [4; 5; 6]
let sumList = List.map2 (fun x y -> x + y) list1 list2
printfn "%A" sumList

La salida es como sigue:

[5; 7; 9]

En el siguiente ejemplo se muestra el uso de List.map3.

let newList2 = List.map3 (fun x y z -> x + y + z) list1 list2 [2; 3; 4]
printfn "%A" newList2

La salida es como sigue:

[7; 10; 13]

En el siguiente ejemplo se muestra el uso de List.mapi.

let newListAddIndex = List.mapi (fun i x -> x + i) list1
printfn "%A" newListAddIndex

La salida es como sigue:

[1; 3; 5]

En el siguiente ejemplo se muestra el uso de List.mapi2.

let listAddTimesIndex = List.mapi2 (fun i x y -> (x + y) * i) list1 list2
printfn "%A" listAddTimesIndex

La salida es como sigue:

[0; 7; 18]

List.collect es como List.map, excepto que cada elemento produce una lista y todas estas listas se concatenan en una lista final. En el código siguiente, cada elemento de la lista genera tres números. Todos ellos se recopilan en una lista.

let collectList = List.collect (fun x -> [for i in 1..3 -> x * i]) list1
printfn "%A" collectList

La salida es como sigue:

[1; 2; 3; 2; 4; 6; 3; 6; 9]

También puede usar List.filter, que toma una condición booleana y produce una nueva lista que consta solo de elementos que cumplen la condición especificada.

let evenOnlyList = List.filter (fun x -> x % 2 = 0) [1; 2; 3; 4; 5; 6]

La lista resultante es [2; 4; 6].

Una combinación de asignación y filtro, List.choose permite transformar y seleccionar elementos al mismo tiempo. List.choose aplica una función que devuelve una opción a cada elemento de una lista, y devuelve una nueva lista de resultados de elementos cuando la función devuelve el valor de opción Some.

El código siguiente muestra cómo usar List.choose para seleccionar las palabras en mayúsculas de una lista de palabras.

let listWords = [ "and"; "Rome"; "Bob"; "apple"; "zebra" ]
let isCapitalized (string1:string) = System.Char.IsUpper string1[0]
let results = List.choose (fun elem ->
    match elem with
    | elem when isCapitalized elem -> Some(elem + "'s")
    | _ -> None) listWords
printfn "%A" results

La salida es como sigue:

["Rome's"; "Bob's"]

Operar en varias listas

Las listas se pueden unir entre sí. Para unir dos listas en una, use List.append. Para unir más de dos listas, use List.concat.

let list1to10 = List.append [1; 2; 3] [4; 5; 6; 7; 8; 9; 10]
let listResult = List.concat [ [1; 2; 3]; [4; 5; 6]; [7; 8; 9] ]
List.iter (fun elem -> printf "%d " elem) list1to10
printfn ""
List.iter (fun elem -> printf "%d " elem) listResult

Operaciones de plegamiento y exploración

Algunas operaciones de lista implican interdependencias entre todos los elementos de lista. Las operaciones de plegamiento y exploración son como List.iter y List.map en cuanto se invoca una función en cada elemento, pero estas operaciones proporcionan un parámetro adicional llamado acumulador que transporta información durante el cálculo.

Use List.fold para realizar un cálculo en una lista.

En el siguiente ejemplo de código se muestra el uso de List.fold para realizar varias operaciones.

La lista se atraviesa; el acumulador acc es un valor que va pasando mientras se realiza el cálculo. El primer argumento toma el acumulador y el elemento de lista y devuelve el resultado provisional del cálculo para ese elemento de lista. El segundo argumento es el valor inicial del acumulador.

let sumList list = List.fold (fun acc elem -> acc + elem) 0 list
printfn "Sum of the elements of list %A is %d." [ 1 .. 3 ] (sumList [ 1 .. 3 ])

// The following example computes the average of a list.
let averageList list = (List.fold (fun acc elem -> acc + float elem) 0.0 list / float list.Length)

// The following example computes the standard deviation of a list.
// The standard deviation is computed by taking the square root of the
// sum of the variances, which are the differences between each value
// and the average.
let stdDevList list =
    let avg = averageList list
    sqrt (List.fold (fun acc elem -> acc + (float elem - avg) ** 2.0 ) 0.0 list / float list.Length)

let testList listTest =
    printfn "List %A average: %f stddev: %f" listTest (averageList listTest) (stdDevList listTest)

testList [1; 1; 1]
testList [1; 2; 1]
testList [1; 2; 3]

// List.fold is the same as to List.iter when the accumulator is not used.
let printList list = List.fold (fun acc elem -> printfn "%A" elem) () list
printList [0.0; 1.0; 2.5; 5.1 ]

// The following example uses List.fold to reverse a list.
// The accumulator starts out as the empty list, and the function uses the cons operator
// to add each successive element to the head of the accumulator list, resulting in a
// reversed form of the list.
let reverseList list = List.fold (fun acc elem -> elem::acc) [] list
printfn "%A" (reverseList [1 .. 10])

Las versiones de estas funciones que tienen un dígito en el nombre de la función operan en más de una lista. Por ejemplo, List.fold2 realiza cálculos en dos listas.

El siguiente ejemplo muestra el uso de List.fold2.

// Use List.fold2 to perform computations over two lists (of equal size) at the same time.
// Example: Sum the greater element at each list position.
let sumGreatest list1 list2 = List.fold2 (fun acc elem1 elem2 ->
                                              acc + max elem1 elem2) 0 list1 list2

let sum = sumGreatest [1; 2; 3] [3; 2; 1]
printfn "The sum of the greater of each pair of elements in the two lists is %d." sum

List.fold y List.scan difiere en que List.fold devuelve el valor final del parámetro adicional, y List.scan devuelve la lista de los valores intermedios (junto con el valor final) del parámetro adicional.

Cada una de estas funciones incluye una variación inversa, por ejemplo, List.foldBack, que difiere en el orden en que se atraviesa la lista y el orden de los argumentos. Además, List.fold y List.foldBack tienen variaciones, List.fold2 y List.foldBack2, que toman dos listas de igual longitud. La función que se ejecuta en cada elemento puede usar los elementos correspondientes de ambas listas para realizar alguna acción. Los tipos de elemento de las dos listas pueden ser diferentes, como en el ejemplo siguiente, en el que una lista contiene importes de transacciones de una cuenta bancaria y la otra lista contiene el tipo de transacción: depósito o retirada.

// Discriminated union type that encodes the transaction type.
type Transaction =
    | Deposit
    | Withdrawal

let transactionTypes = [Deposit; Deposit; Withdrawal]
let transactionAmounts = [100.00; 1000.00; 95.00 ]
let initialBalance = 200.00

// Use fold2 to perform a calculation on the list to update the account balance.
let endingBalance = List.fold2 (fun acc elem1 elem2 ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2)
                                initialBalance
                                transactionTypes
                                transactionAmounts
printfn "%f" endingBalance

Para un cálculo como la suma, List.fold y List.foldBack tiene el mismo efecto porque el resultado no depende del orden del recorrido. En el ejemplo siguientes, se usa List.foldBack para sumar los elementos de una lista.

let sumListBack list = List.foldBack (fun elem acc -> acc + elem) list 0
printfn "%d" (sumListBack [1; 2; 3])

// For a calculation in which the order of traversal is important, fold and foldBack have different
// results. For example, replacing fold with foldBack in the listReverse function
// produces a function that copies the list, rather than reversing it.
let copyList list = List.foldBack (fun elem acc -> elem::acc) list []
printfn "%A" (copyList [1 .. 10])

El ejemplo siguiente vuelve al ejemplo de la cuenta bancaria. Esta vez, se agrega un nuevo tipo de transacción: un cálculo de intereses. El saldo final depende ahora del orden de las transacciones.

type Transaction2 =
    | Deposit
    | Withdrawal
    | Interest

let transactionTypes2 = [Deposit; Deposit; Withdrawal; Interest]
let transactionAmounts2 = [100.00; 1000.00; 95.00; 0.05 / 12.0 ]
let initialBalance2 = 200.00

// Because fold2 processes the lists by starting at the head element,
// the interest is calculated last, on the balance of 1205.00.
let endingBalance2 = List.fold2 (fun acc elem1 elem2 ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2
                                | Interest -> acc * (1.0 + elem2))
                                initialBalance2
                                transactionTypes2
                                transactionAmounts2
printfn "%f" endingBalance2


// Because foldBack2 processes the lists by starting at end of the list,
// the interest is calculated first, on the balance of only 200.00.
let endingBalance3 = List.foldBack2 (fun elem1 elem2 acc ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2
                                | Interest -> acc * (1.0 + elem2))
                                transactionTypes2
                                transactionAmounts2
                                initialBalance2
printfn "%f" endingBalance3

La función List.reduce es en cierto modo parecida a List.fold y List.scan, excepto que en lugar de pasar un acumulador diferente, List.reduce toma una función que toma dos argumentos del tipo de elemento en lugar de solo uno, y uno de esos argumentos actúa como acumulador, lo que significa que almacena el resultado intermedio del cálculo. List.reduce comienza por operar en los dos primeros elementos y, después, usa el resultado de la operación con el siguiente elemento. Como no hay un acumulador diferente que tenga su propio tipo, se puede usar List.reduce en lugar de List.fold solo cuando el acumulador y el elemento sean del mismo tipo. En el código siguiente se muestra cómo usar List.reduce. List.reduce activa una excepción si la lista proporciona no tiene elementos.

En el código siguiente, en la primera llamada a la expresión lambda se proporcionan los argumentos 2 y 4, y devuelve 6; en la siguiente llamada se proporcionan los argumentos 6 y 10, por lo que el resultado es 16.

let sumAList list =
    try
        List.reduce (fun acc elem -> acc + elem) list
    with
       | :? System.ArgumentException as exc -> 0

let resultSum = sumAList [2; 4; 10]
printfn "%d " resultSum

Convertir entre listas y otros tipos de colecciones

El módulo List proporciona funciones para convertir desde y hacia secuencias y matrices. Para convertir hacia o desde una secuencia, use List.toSeq o List.ofSeq. Para convertir hacia o desde una matriz, use List.toArray o List.ofArray.

Otras operaciones

Para obtener información sobre otras operaciones en listas, vea el tema de referencia de la biblioteca Módulo List.

Vea también