Partilhar via


Listas

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 List.

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 os 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 são mais longas ou quando você deseja incluir um comentário para cada elemento.

let list123 = [ 1; 2; 3 ]

Normalmente, todos os elementos da lista devem ser do mesmo tipo. Uma exceção é que uma lista na qual os elementos são especificados como sendo um tipo base pode ter elementos que são tipos derivados. Assim, o seguinte é aceitável, porque ambos e ButtonCheckBox 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 é [2; 3; 4] e list2 é [100; 2; 3; 4], este código cria 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 List.

Como as listas em F# são imutáveis, qualquer operação de modificação gera novas listas em vez de modificar listas existentes.

As listas em F# são implementadas como listas vinculadas individualmente, o que significa que as operações que acessam apenas o cabeçalho da lista são O(1) e o acesso ao elemento é O(n).

Propriedades

O tipo de lista suporta as seguintes propriedades:

Propriedade Type Description
Cabeça 'T O primeiro elemento.
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.
Cauda 'T list A lista sem o primeiro elemento.

A seguir estão alguns exemplos de uso dessas 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 executar operações complexas com uma pequena quantidade de código. Esta seção descreve operações comuns em listas que são importantes para a programação funcional.

Recursão com listas

As listas são exclusivamente adequadas para técnicas de programação recursiva. Considere uma operação que deve ser executada em cada elemento de uma lista. Você pode fazer isso recursivamente operando no cabeçalho da lista e, em seguida, passando a cauda da lista, que é uma lista menor que consiste na lista original sem o primeiro elemento, de volta para o próximo nível de recursão.

Para escrever essa função recursiva, você usa o operador contras (::) na correspondência de padrões, o que permite separar o cabeçalho de uma lista da cauda.

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, pode transbordar a pilha. O código a seguir melhora esse código usando um argumento de acumulador, uma técnica padrão para trabalhar com funções recursivas. O uso do argumento acumulador torna a cauda 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 os números devem ser removidos. 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)

O resultado é o 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 do módulo

O módulo Lista fornece funções que acessam os elementos de uma lista. O elemento cabeça é o mais rápido e fácil de aceder. Use a propriedade Head ou a função de módulo List.head. Você pode acessar a cauda 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 atravessa a lista. Portanto, é O(n). Se o código for usado List.nth com frequência, convém considerar o uso de uma matriz em vez de uma lista. O acesso ao elemento em matrizes é O(1).

Operações booleanas em listas

A função List.isEmpty determina se uma lista tem algum elemento .

A função List.exists aplica um teste booleano aos elementos de uma lista e retorna true se algum elemento satisfizer o teste. List.exists2 é semelhante, mas opera em pares sucessivos de elementos em duas listas.

O código a seguir demonstra o uso do 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)

O resultado é o 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

O resultado é o 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])

O resultado é o seguinte:

true
false

Da mesma forma, List.forall2 determina se todos os elementos nas posições correspondentes em duas listas satisfazem uma expressão booleana 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])

O resultado é o seguinte:

true
false

Ordenar operações em listas

As funções List.sort, List.sortBy e List.sortWith classificam listas. A função de classificação determina qual dessas três funções deve ser usada. 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 de forma eficiente 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 da 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 pequenos tipos estruturados; 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 que é usado como critério de classificação e List.sortWith usa uma função de comparação como um argumento. Essas duas últimas funções são úteis quando você está trabalhando com tipos que não suportam 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

O resultado é o 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

O resultado é o seguinte:

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

O próximo exemplo demonstra o uso de List.sortWith. Neste exemplo, a função compareWidgets de comparação personalizada é usada para primeiro 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

O resultado é o 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 são suportadas para listas. O mais simples, List.find, permite que você encontre o primeiro elemento que corresponde a uma determinada condição.

O exemplo de código a seguir demonstra o uso de List.find para 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 valor da primeira 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 lança 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

O resultado é o 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 tal elemento existir, mas o valor None da opção se não. A variação List.tryFindIndex retorna o índice do elemento, se 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."

O resultado é o 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 no módulo List. Para trabalhar com List.sum, o tipo de elemento list deve suportar o + operador e ter um valor zero. Todos os tipos aritméticos incorporados satisfazem estas condições. Para trabalhar com List.average, o tipo de elemento deve suportar a divisão sem um restante, o que exclui tipos integrais, mas permite tipos de ponto flutuante. As funções List.sumBy e List.averageBy tomam uma função como parâmetro, e os resultados dessa função são usados para calcular os valores para a soma ou 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

O resultado é 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

O resultado é 5.5.

Listas e Tuplas

As listas que contêm tuplas podem ser manipuladas pelas funções zip e unzip. 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 tuplas. Outra versão, List.zip3, pega 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

O resultado é o 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

O resultado é o seguinte:

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

As versões descompactadas correspondentes, List.unzip e List.unzip3, tomam 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)

O resultado é o 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

O resultado é o seguinte:

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

Operando em elementos de lista

O F# suporta uma variedade de operações em elementos de lista. O mais simples é List.iter, que permite chamar 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

O resultado é o 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 usam várias listas. Você também pode usar List.mapi e List.mapi2, se, além do elemento, a função precisa ser passada o í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

O resultado é o 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

O resultado é o 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

O resultado é o 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

O resultado é o 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

O resultado é o 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. Estes são todos reunidos em uma lista.

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

O resultado é o seguinte:

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

Você também pode usar List.filter, que usa uma condição booleana e produz uma nova lista que consiste apenas em elementos que satisfazem a 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 para cada elemento de uma lista e retorna uma nova lista dos resultados para elementos quando a função retorna o valor Someda opção .

O código a seguir demonstra o uso de List.choose para selecionar palavras 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

O resultado é o seguinte:

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

Operando em várias listas

As listas podem ser unidas. Para unir duas listas em uma, use List.append. Para unir 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 dobragem e varredura

Algumas operações de lista envolvem interdependências entre todos os elementos da lista. As operações de dobra e varredura são como List.iter e List.map em que você invoca uma função em cada elemento, mas essas operações fornecem um parâmetro adicional chamado acumulador que carrega informações através do cálculo.

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 que é repassado à medida que o cálculo prossegue. O primeiro argumento usa o acumulador e o elemento list 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 na medida 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 tomam duas listas de igual comprimento. A função que é executada em cada elemento pode usar elementos correspondentes de ambas as listas para executar alguma ação. Os tipos de elementos 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 ter o mesmo efeito porque o resultado não depende da ordem de travessia. 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 como List.fold e List.scan, exceto que, em vez de passar um acumulador separado, List.reduce toma 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 armazena o resultado intermediário do cálculo. List.reduce Começa operando nos dois primeiros elementos da 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 no lugar de apenas quando o acumulador e o tipo de List.fold elemento têm o mesmo tipo. O código a seguir demonstra o uso do List.reduce. List.reduce lança 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 conversão de e para sequências e matrizes. Para converter para ou a partir de uma sequência, use List.toSeq ou List.ofSeq. Para converter para ou de uma matriz, use List.toArray ou List.ofArray.

Operações adicionais

Para obter informações sobre operações adicionais em listas, consulte o tópico de referência da biblioteca List Module.

Consulte também