Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Uma lista em F# é uma série ordenada e imutável de elementos do mesmo tipo. Para executar operações básicas em listas, use as funções no módulo Lista.
Criando e inicializando listas
Você pode definir uma lista listando explicitamente os elementos, separados por ponto-e-vírgula e entre colchetes, conforme mostrado na linha de código a seguir.
let list123 = [ 1; 2; 3 ]
Você também pode colocar quebras de linha entre elementos, caso em que os ponto e vírgula são opcionais. A última sintaxe pode resultar em um código mais legível quando as expressões de inicialização do elemento forem mais longas ou quando você quiser incluir um comentário para cada elemento.
let list123 = [ 1; 2; 3 ]
Normalmente, todos os elementos de lista devem ser do mesmo tipo. Uma exceção é que uma lista na qual os elementos são especificados para ser um tipo base pode ter elementos que são tipos derivados. Portanto, o seguinte é aceitável, pois ambos Button e CheckBox derivam de Control.
let myControlList: Control list = [ new Button(); new CheckBox() ]
Você também pode definir elementos de lista usando um intervalo indicado por inteiros separados pelo operador de intervalo (..), conforme mostrado no código a seguir.
let list1 = [ 1..10 ]
Uma lista vazia é especificada por um par de colchetes sem nada entre eles.
// An empty list.
let listEmpty = []
Você também pode usar uma expressão de sequência para criar uma lista. Consulte expressões de sequência para obter mais informações. Por exemplo, o código a seguir cria uma lista de quadrados de inteiros de 1 a 10.
let listOfSquares = [ for i in 1..10 -> i * i ]
Operadores para trabalhar com listas
Você pode anexar elementos a uma lista usando o :: operador (contras). Se list1 for [2; 3; 4], o código a seguir cria list2 como [100; 2; 3; 4].
let list2 = 100 :: list1
Você pode concatenar listas que têm tipos compatíveis usando o @ operador, como no código a seguir. Se list1 for [2; 3; 4] e list2 for [100; 2; 3; 4], esse código será criado list3 como [2; 3; 4; 100; 2; 3; 4].
let list3 = list1 @ list2
As funções para executar operações em listas estão disponíveis no módulo Lista.
Como as listas em F# são imutáveis, todas as operações de modificação geram novas listas em vez de modificar listas existentes.
As listas em F# são implementadas como listas vinculadas, o que significa que as operações que acessam apenas o cabeçalho da lista são O(1) e o acesso a elementos é O(n).
Propriedades
O tipo de lista dá suporte às seguintes propriedades:
| Propriedade | Tipo | Descrição |
|---|---|---|
| Head | 'T |
O primeiro elemento. |
| Empty (vazio) | 'T list |
Uma propriedade estática que retorna uma lista vazia do tipo apropriado. |
| IsEmpty | bool |
true se a lista não tiver elementos. |
| Item | 'T |
O elemento no índice especificado (baseado em zero). |
| comprimento | int |
O número de elementos. |
| Tail | 'T list |
A lista sem o primeiro elemento. |
A seguir estão alguns exemplos de como usar essas propriedades.
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))
Usando listas
A programação com listas permite que você execute operações complexas com uma pequena quantidade de código. Esta seção descreve operações comuns em listas importantes para a programação funcional.
Recursão com listas
As listas são exclusivamente adequadas para técnicas de programação recursivas. Considere uma operação que deve ser executada em cada elemento de uma lista. Você pode fazer isso recursivamente operando na cabeça da lista e passando a parte final da lista, que é uma lista menor que consiste na lista original sem o primeiro elemento, novamente para o próximo nível de recursão.
Para escrever essa função recursiva, use o operador contras (::) na correspondência de padrões, o que permite separar o cabeçalho de uma lista da parte final.
O exemplo de código a seguir mostra como usar a correspondência de padrões para implementar uma função recursiva que executa operações em uma lista.
let rec sum list =
match list with
| head :: tail -> head + sum tail
| [] -> 0
O código anterior funciona bem para listas pequenas, mas para listas maiores, ele pode estourar a pilha. O código a seguir melhora esse código usando um argumento acumulador, uma técnica padrão para trabalhar com funções recursivas. O uso do argumento acumulador torna a parte final da função recursiva, o que economiza espaço na pilha.
let sum list =
let rec loop list acc =
match list with
| head :: tail -> loop tail (acc + head)
| [] -> acc
loop list 0
A função RemoveAllMultiples é uma função recursiva que usa duas listas. A primeira lista contém os números cujos múltiplos serão removidos e a segunda lista é a lista da qual remover os números. O código no exemplo a seguir usa essa função recursiva para eliminar todos os números não primos de uma lista, deixando uma lista de números primos como resultado.
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)
A saída é a seguinte:
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]
Funções de módulo
O módulo Lista fornece funções que acessam os elementos de uma lista. O elemento principal é o mais rápido e fácil de acessar. Use a propriedade Head ou a função de módulo List.head. Você pode acessar a parte final de uma lista usando a propriedade Tail ou a função List.tail . Para localizar um elemento por índice, use a função List.nth .
List.nth percorre a lista. Portanto, é O(n). Se o código for usado List.nth com frequência, talvez você queira considerar o uso de uma matriz em vez de uma lista. O acesso de elemento em matrizes é O(1).
Operações boolianas em listas
A função List.isEmpty determina se uma lista tem elementos.
A função List.exists aplica um teste booliano a elementos de uma lista e retorna true se algum elemento satisfaz o teste.
List.exists2 é semelhante, mas opera em pares sucessivos de elementos em duas listas.
O código a seguir demonstra o uso de 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)
A saída é a seguinte:
For list [0; 1; 2; 3], contains zero is true
O exemplo a seguir demonstra o 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
A saída é a seguinte:
Lists [1; 2; 3; 4; 5] and [5; 4; 3; 2; 1] have at least one equal element at the same position.
Você pode usar List.forall se quiser testar se todos os elementos de uma lista atendem a uma condição.
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])
A saída é a seguinte:
true
false
Da mesma forma, List.forall2 determina se todos os elementos nas posições correspondentes em duas listas atendem a uma expressão booliana que envolve 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])
A saída é a seguinte:
true
false
Operações de classificação em listas
As listas de classificação de funções List.sort, List.sortBy e List.sortWith . A função de classificação determina quais dessas três funções usar.
List.sort usa comparação genérica padrão. A comparação genérica usa operadores globais com base na função de comparação genérica para comparar valores. Ele funciona com eficiência com uma ampla variedade de tipos de elementos, como tipos numéricos simples, tuplas, registros, uniões discriminadas, listas, matrizes e qualquer tipo que implemente System.IComparable. Para tipos que implementam System.IComparable, a comparação genérica usa a System.IComparable.CompareTo() função. A comparação genérica também funciona com cadeias de caracteres, mas usa uma ordem de classificação independente de cultura. A comparação genérica não deve ser usada em tipos sem suporte, como tipos de função. Além disso, o desempenho da comparação genérica padrão é melhor para tipos estruturados pequenos; para tipos estruturados maiores que precisam ser comparados e classificados com frequência, considere implementar System.IComparable e fornecer uma implementação eficiente do System.IComparable.CompareTo() método.
List.sortBy usa uma função que retorna um valor usado como critério de classificação e List.sortWith usa uma função de comparação como argumento. Essas duas últimas funções são úteis quando você está trabalhando com tipos que não dão suporte à comparação ou quando a comparação requer semântica de comparação mais complexa, como no caso de cadeias de caracteres com reconhecimento de cultura.
O exemplo a seguir demonstra o uso de List.sort.
let sortedList1 = List.sort [1; 4; 8; -2; 5]
printfn "%A" sortedList1
A saída é a seguinte:
[-2; 1; 4; 5; 8]
O exemplo a seguir demonstra o uso de List.sortBy.
let sortedList2 = List.sortBy (fun elem -> abs elem) [1; 4; 8; -2; 5]
printfn "%A" sortedList2
A saída é a seguinte:
[1; -2; 4; 5; 8]
O exemplo a seguir demonstra o uso de List.sortWith. Neste exemplo, a função compareWidgets de comparação personalizada é usada primeiro para comparar um campo de um tipo personalizado e, em seguida, outro quando os valores do primeiro campo são iguais.
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
A saída é a seguinte:
[{ID = 92;
Rev = 1;}; {ID = 92;
Rev = 1;}; {ID = 100;
Rev = 2;}; {ID = 100;
Rev = 5;}; {ID = 110;
Rev = 1;}]
Operações de pesquisa em listas
Várias operações de pesquisa têm suporte para listas. O mais simples, List.find, permite localizar o primeiro elemento que corresponde a uma determinada condição.
O exemplo de código a seguir demonstra o uso de List.find localizar o primeiro número que é divisível por 5 em uma lista.
let isDivisibleBy number elem = elem % number = 0
let result = List.find (isDivisibleBy 5) [ 1 .. 100 ]
printfn "%d " result
O resultado é 5.
Se os elementos precisarem ser transformados primeiro, chame List.pick, que usa uma função que retorna uma opção e procura o primeiro valor de opção que é Some(x). Em vez de retornar o elemento, List.pick retorna o resultado x. Se nenhum elemento correspondente for encontrado, List.pick gerará System.Collections.Generic.KeyNotFoundException. O código a seguir mostra o 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
A saída é a seguinte:
"b"
Outro grupo de operações de pesquisa, List.tryFind e funções relacionadas, retorna um valor de opção. A List.tryFind função retorna o primeiro elemento de uma lista que satisfaz uma condição se esse elemento existir, mas o valor None da opção, caso contrário. A variação List.tryFindIndex retornará o índice do elemento, se um for encontrado, em vez do elemento em si. Essas funções são ilustradas no código a seguir.
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."
A saída é a seguinte:
The first even value is 22.
The first even value is at position 8.
Operações aritméticas em listas
Operações aritméticas comuns, como soma e média, são incorporadas ao módulo Lista. Para trabalhar com List.sum, o tipo de elemento de lista deve dar suporte ao + operador e ter um valor zero. Todos os tipos aritméticos internos atendem a essas condições. Para trabalhar com List.average, o tipo de elemento deve dar suporte à divisão sem um restante, o que exclui tipos integrais, mas permite tipos de ponto flutuante. As funções List.sumBy e List.averageBy assumem uma função como parâmetro e os resultados dessa função são usados para calcular os valores da soma ou da média.
O código a seguir demonstra o uso de List.sum, List.sumBye 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
A saída é 1.000000.
O código a seguir mostra o uso de List.averageBy.
let avg2 = List.averageBy (fun elem -> float elem) [1 .. 10]
printfn "%f" avg2
A saída é 5.5.
Listas e Tuplas
Listas que contêm tuplas podem ser manipuladas por funções zip e descompactada. Essas funções combinam duas listas de valores únicos em uma lista de tuplas ou separam uma lista de tuplas em duas listas de valores únicos. A função List.zip mais simples usa duas listas de elementos únicos e produz uma única lista de pares de tupla. Outra versão, List.zip3, usa três listas de elementos únicos e produz uma única lista de tuplas que têm três elementos. O exemplo de código a seguir demonstra o uso de List.zip.
let list1 = [ 1; 2; 3 ]
let list2 = [ -1; -2; -3 ]
let listZip = List.zip list1 list2
printfn "%A" listZip
A saída é a seguinte:
[(1, -1); (2, -2); (3; -3)]
O exemplo de código a seguir demonstra o uso de List.zip3.
let list3 = [ 0; 0; 0]
let listZip3 = List.zip3 list1 list2 list3
printfn "%A" listZip3
A saída é a seguinte:
[(1, -1, 0); (2, -2, 0); (3, -3, 0)]
As versões descompactadas correspondentes, List.unzip e List.unzip3, pegam listas de tuplas e listas de retorno em uma tupla, onde a primeira lista contém todos os elementos que foram os primeiros em cada tupla, e a segunda lista contém o segundo elemento de cada tupla e assim por diante.
O exemplo de código a seguir demonstra o uso de List.unzip.
let lists = List.unzip [(1,2); (3,4)]
printfn "%A" lists
printfn "%A %A" (fst lists) (snd lists)
A saída é a seguinte:
([1; 3], [2; 4])
[1; 3] [2; 4]
O exemplo de código a seguir demonstra o uso de List.unzip3.
let listsUnzip3 = List.unzip3 [(1,2,3); (4,5,6)]
printfn "%A" listsUnzip3
A saída é a seguinte:
([1; 4], [2; 5], [3; 6])
Operando em elementos de lista
O F# dá suporte a uma variedade de operações em elementos de lista. O mais simples é List.iter, que permite que você chame uma função em cada elemento de uma lista. As variações incluem List.iter2, que permite executar uma operação em elementos de duas listas, List.iteri, que é como List.iter exceto que o índice de cada elemento é passado como um argumento para a função que é chamada para cada elemento, e List.iteri2, que é uma combinação da funcionalidade de List.iter2 e List.iteri. O exemplo de código a seguir ilustra essas funções.
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
A saída é a seguinte:
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
Outra função usada com frequência que transforma elementos de lista é List.map, que permite aplicar uma função a cada elemento de uma lista e colocar todos os resultados em uma nova lista.
List.map2 e List.map3 são variações que levam várias listas. Você também pode usar List.mapi e List.mapi2 se, além do elemento, a função precisar ser passada pelo índice de cada elemento. A única diferença entre List.mapi2 e List.mapi é que List.mapi2 funciona com duas listas. O exemplo a seguir ilustra List.map.
let list1 = [1; 2; 3]
let newList = List.map (fun x -> x + 1) list1
printfn "%A" newList
A saída é a seguinte:
[2; 3; 4]
O exemplo a seguir mostra o 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
A saída é a seguinte:
[5; 7; 9]
O exemplo a seguir mostra o uso de List.map3.
let newList2 = List.map3 (fun x y z -> x + y + z) list1 list2 [2; 3; 4]
printfn "%A" newList2
A saída é a seguinte:
[7; 10; 13]
O exemplo a seguir mostra o uso de List.mapi.
let newListAddIndex = List.mapi (fun i x -> x + i) list1
printfn "%A" newListAddIndex
A saída é a seguinte:
[1; 3; 5]
O exemplo a seguir mostra o uso de List.mapi2.
let listAddTimesIndex = List.mapi2 (fun i x y -> (x + y) * i) list1 list2
printfn "%A" listAddTimesIndex
A saída é a seguinte:
[0; 7; 18]
List.collect é como List.map, exceto que cada elemento produz uma lista e todas essas listas são concatenadas em uma lista final. No código a seguir, cada elemento da lista gera três números. Todos eles são coletados em uma lista.
let collectList = List.collect (fun x -> [for i in 1..3 -> x * i]) list1
printfn "%A" collectList
A saída é a seguinte:
[1; 2; 3; 2; 4; 6; 3; 6; 9]
Você também pode usar List.filter, que usa uma condição booliana e produz uma nova lista que consiste apenas em elementos que atendem à condição fornecida.
let evenOnlyList = List.filter (fun x -> x % 2 = 0) [1; 2; 3; 4; 5; 6]
A lista resultante é [2; 4; 6].
Uma combinação de mapa e filtro, List.choose permite transformar e selecionar elementos ao mesmo tempo.
List.choose aplica uma função que retorna uma opção a cada elemento de uma lista e retorna uma nova lista dos resultados dos elementos quando a função retorna o valor Someda opção.
O código a seguir demonstra o uso de List.choose palavras maiúsculas em maiúsculas de uma lista de palavras.
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
A saída é a seguinte:
["Rome's"; "Bob's"]
Operando em várias listas
As listas podem ser unidas. Para ingressar duas listas em uma, use List.append. Para ingressar em mais de duas 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
Operações de dobra e verificação
Algumas operações de lista envolvem interdependências entre todos os elementos de lista. As operações de dobra e verificação são semelhantes List.iter e List.map , em seguida, você invoca uma função em cada elemento, mas essas operações fornecem um parâmetro adicional chamado acumulador que carrega informações por meio da computação.
Use List.fold para executar um cálculo em uma lista.
O exemplo de código a seguir demonstra o uso de List.fold para executar várias operações.
A lista é percorrida; o acumulador acc é um valor passado à medida que o cálculo prossegue. O primeiro argumento usa o acumulador e o elemento de lista e retorna o resultado provisório do cálculo para esse elemento de lista. O segundo argumento é o valor inicial do 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])
As versões dessas funções que têm um dígito no nome da função operam em mais de uma lista. Por exemplo, List.fold2 executa cálculos em duas listas.
O exemplo a seguir demonstra o 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 e List.scan diferem em que List.fold retorna o valor final do parâmetro extra, mas List.scan retorna a lista dos valores intermediários (juntamente com o valor final) do parâmetro extra.
Cada uma dessas funções inclui uma variação inversa, por exemplo, List.foldBack, que difere na ordem em que a lista é percorrida e na ordem dos argumentos. Além disso, List.fold e List.foldBack têm variações, List.fold2 e List.foldBack2, que levam duas listas de comprimento igual. A função executada em cada elemento pode usar elementos correspondentes de ambas as listas para executar alguma ação. Os tipos de elemento das duas listas podem ser diferentes, como no exemplo a seguir, em que uma lista contém valores de transação para uma conta bancária e a outra lista contém o tipo de transação: depósito ou 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 um cálculo como soma, List.fold e List.foldBack tenha o mesmo efeito porque o resultado não depende da ordem de passagem. No exemplo a seguir, List.foldBack é usado para adicionar os elementos em uma 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])
O exemplo a seguir retorna ao exemplo de conta bancária. Desta vez, um novo tipo de transação é adicionado: um cálculo de juros. O saldo final agora depende da ordem das transações.
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
A função List.reduce é um pouco semelhante List.fold e List.scan, exceto que, em vez de passar um acumulador separado, List.reduce usa uma função que usa dois argumentos do tipo de elemento em vez de apenas um, e um desses argumentos atua como o acumulador, o que significa que ele armazena o resultado intermediário da computação.
List.reduce começa operando nos dois primeiros elementos de lista e, em seguida, usa o resultado da operação junto com o próximo elemento. Como não há um acumulador separado que tenha seu próprio tipo, List.reduce pode ser usado somente quando List.fold o acumulador e o tipo de elemento tiverem o mesmo tipo. O código a seguir demonstra o uso de List.reduce.
List.reduce gerará uma exceção se a lista fornecida não tiver elementos.
No código a seguir, a primeira chamada para a expressão lambda recebe os argumentos 2 e 4 e retorna 6, e a próxima chamada recebe os argumentos 6 e 10, portanto, o resultado é 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
Convertendo entre listas e outros tipos de coleção
O List módulo fornece funções para converter de e para sequências e matrizes. Para converter de ou para uma sequência, use List.toSeq ou List.ofSeq. Para converter de ou para uma matriz, use List.toArray ou List.ofArray.
Operações adicionais
Para obter informações sobre operações adicionais em listas, consulte o módulo de lista de tópicos de referência da biblioteca.