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 secuencia para 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 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.
Las listas de F# se implementan como listas vinculadas de forma única, lo que significa que las operaciones que tienen acceso solo al responsable de la lista son O(1) y el acceso a 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). |
| Duración | 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 Lista proporciona funciones que tienen acceso 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 de módulo List.head. Puede acceder al final de una lista mediante 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 elementos.
La función List.exists aplica una prueba booleana a los elementos de una lista y devuelve true si algún elemento satisface la prueba. List.exists2 es similar, pero funciona en pares sucesivos de elementos en 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 desea 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 de las posiciones correspondientes de dos listas satisfacen una expresión booleana que implica 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
Listas de ordenación de funciones List.sort, List.sortByy List.sortWith. 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. El más sencillo, List.find, le permite encontrar el primer elemento que coincide con una condición determinada.
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 opción que es 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, devuelven 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 uno, 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 sum y average, se integran en el módulo List. Para trabajar con List.sum, el tipo de elemento list debe admitir el + operador y tener un valor 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 un resto, lo que excluye los tipos enteros, pero permite 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 de List.zip más sencilla toma dos listas de elementos únicos y genera una única lista de pares de tupla. Otra versión, List.zip3,toma tres listas de elementos únicos y genera una única 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 de descompresión correspondientes, List.unzip y List.unzip3,toman listas de tuplas y listas de retorno en una tupla, donde la primera lista contiene todos los elementos que estaban en primer lugar en cada tupla, y la segunda lista contiene el segundo elemento de cada tupla, y así sucesivamente.
En el ejemplo de código siguiente 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 ejemplo de código siguiente 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. El más sencillo es List.iter,que permite llamar a una función en cada elemento de una lista. Entre las variaciones se incluyen List.iter2, que permite realizar una operación en elementos de dos listas, List.iteri, que es como , salvo que el índice de cada elemento se pasa como argumento a la función a la que se llama para cada elemento, y List.iter 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 usada con frecuencia 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 nueva lista. List.map2 y List.map3 son variaciones que toman varias listas. También puede usar List.mapi y List.mapi2si, 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 , salvo que cada elemento genera una lista y todas estas listas List.map 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 genera una nueva lista que consta solo de elementos que satisfacen la condición dada.
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 le 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 a 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 examen son como y en que se invoca una función en cada elemento, pero estas operaciones proporcionan un parámetro adicional denominado acumulador que lleva información a través List.iter List.map del cálculo.
Use List.fold para realizar un cálculo en una lista.
En el ejemplo de código siguiente 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 difieren en que devuelve el valor final del parámetro adicional, pero devuelve la lista de los valores intermedios (junto con el List.fold valor List.scan 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 recorre la lista y en 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 elementos de las dos listas pueden ser diferentes, como en el ejemplo siguiente, en el que una lista contiene importes de transacción para 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 interés. 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 similar a y , salvo que, en lugar de pasar por un acumulador independiente, toma una función que toma dos argumentos del tipo de elemento en lugar de uno solo, y uno de esos argumentos actúa como el List.fold List.scan acumulador, lo que significa que almacena el resultado intermedio del List.reduce 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 a o desde una secuencia, use List.toSeq o List.ofSeq. Para convertir a o desde una matriz, use List.toArray o List.ofArray.
Otras operaciones
Para obtener información sobre las operaciones adicionales en las listas, vea el tema de referencia de biblioteca List Module.