Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Список в F# — это упорядоченный, неизменяемый ряд элементов одного типа. Чтобы выполнить основные операции со списками, используйте функции в модуле List.
Создание и инициализация списков
Список можно определить, явно перечислив элементы, разделенные точкой с запятой и заключенные в квадратные скобки, как показано в следующей строке кода.
let list123 = [ 1; 2; 3 ]
Можно также поместить разрывы линий между элементами, в этом случае точки с запятой являются необязательными. Последний синтаксис может привести к более читаемому коду, если выражения инициализации элемента длиннее или если требуется включить комментарий для каждого элемента.
let list123 = [ 1; 2; 3 ]
Как правило, все элементы списка должны быть одинаковыми. Исключение заключается в том, что список, в котором элементы указываются для базового типа, могут иметь элементы, производные от типов. Таким образом, ниже допустимо, так как оба Button и CheckBox производные от Control.
let myControlList: Control list = [ new Button(); new CheckBox() ]
Можно также определить элементы списка с помощью диапазона, указанного целыми числами, разделенными оператором диапазона (..), как показано в следующем коде.
let list1 = [ 1..10 ]
Пустой список задается парой квадратных скобок без ничего между ними.
// An empty list.
let listEmpty = []
Для создания списка можно также использовать выражение последовательности. Дополнительные сведения см. в разделе "Выражения последовательности ". Например, следующий код создает список квадратов целых чисел от 1 до 10.
let listOfSquares = [ for i in 1..10 -> i * i ]
Операторы для работы со списками
Элементы можно присоединить к списку :: с помощью оператора (cons). В list1 противном случае [2; 3; 4]следующий код создает list2 как [100; 2; 3; 4].
let list2 = 100 :: list1
Списки с совместимыми типами можно объединить с помощью @ оператора, как показано в следующем коде. Если list1 это и list2 есть[100; 2; 3; 4][2; 3; 4], этот код создает list3 как [2; 3; 4; 100; 2; 3; 4].
let list3 = list1 @ list2
Функции для выполнения операций со списками доступны в модуле List.
Так как списки в F# неизменяемы, все операции изменения создают новые списки вместо изменения существующих списков.
Списки в F# реализуются как последовательно связанные списки, что означает, что операции, обращающиеся только к голове списка, являются O(1), а доступ к элементу — O(n).
Свойства
Тип списка поддерживает следующие свойства:
| Недвижимость | Тип | Описание |
|---|---|---|
| головы | 'T |
Первый элемент. |
| Пусто | 'T list |
Статическое свойство, возвращающее пустой список соответствующего типа. |
| IsEmpty | bool |
true Значение , если в списке нет элементов. |
| Элемент | 'T |
Элемент по указанному индексу (отсчитывается от нуля). |
| Длина | int |
Количество элементов. |
| Tail | 'T list |
Список без первого элемента. |
Ниже приведены некоторые примеры использования этих свойств.
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))
Использование списков
Программирование со списками позволяет выполнять сложные операции с небольшим количеством кода. В этом разделе описываются распространенные операции со списками, которые важны для функционального программирования.
Рекурсия со списками
Списки уникальны подходят для рекурсивных методов программирования. Рассмотрим операцию, которая должна выполняться для каждого элемента списка. Это можно сделать рекурсивно, работая с головой списка, а затем передав хвост списка, который состоит из исходного списка без первого элемента, еще раз на следующий уровень рекурсии.
Чтобы написать такую рекурсивную функцию, используйте оператор cons (::) в сопоставлении шаблонов, что позволяет отделять голову списка от хвоста.
В следующем примере кода показано, как использовать сопоставление шаблонов для реализации рекурсивной функции, выполняющей операции в списке.
let rec sum list =
match list with
| head :: tail -> head + sum tail
| [] -> 0
Предыдущий код хорошо подходит для небольших списков, но для больших списков он может переполнение стека. Следующий код улучшает этот код с помощью аргумента аккумулятора, стандартного метода для работы с рекурсивных функций. Использование аргумента аккумулятора делает функцию рекурсивной, которая экономит пространство стека.
let sum list =
let rec loop list acc =
match list with
| head :: tail -> loop tail (acc + head)
| [] -> acc
loop list 0
Функция — это рекурсивная функция RemoveAllMultiples , которая принимает два списка. Первый список содержит числа, несколько которых будут удалены, а второй — список, из которого нужно удалить числа. Код в следующем примере использует эту рекурсивную функцию для устранения всех незначевых чисел из списка, оставляя список простых чисел в качестве результата.
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)
Выходные данные приведены следующим образом:
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]
Функции модуля
Модуль List предоставляет функции, которые обращаются к элементам списка. Головной элемент является самым быстрым и простым для доступа. Используйте свойство Head или module function List.head. Вы можете получить доступ к хвосту списка с помощью свойства Tail или функции List.tail . Чтобы найти элемент по индексу, используйте функцию List.nth .
List.nth проходит по списку. Таким образом, это O(n). Если код часто используется List.nth , может потребоваться использовать массив вместо списка. Доступ к элементам в массивах — O(1).
Логические операции в списках
Функция List.isEmpty определяет, содержит ли список элементы.
Функция List.exists применяет логический тест к элементам списка и возвращает, true если любой элемент удовлетворяет тесту.
List.exists2 похож на последовательные пары элементов в двух списках.
В следующем коде показано использование 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)
Выходные данные приведены следующим образом:
For list [0; 1; 2; 3], contains zero is true
В следующем примере показано использование 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
Выходные данные приведены следующим образом:
Lists [1; 2; 3; 4; 5] and [5; 4; 3; 2; 1] have at least one equal element at the same position.
Можно использовать List.forall , если вы хотите проверить, соответствуют ли все элементы списка условию.
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])
Выходные данные приведены следующим образом:
true
false
Аналогичным образом List.forall2 определяет, соответствуют ли все элементы в соответствующих позициях в двух списках логическим выражением, которое включает каждую пару элементов.
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])
Выходные данные приведены следующим образом:
true
false
Операции сортировки по спискам
Списки сортировки функций List.sort,List.sortBy и List.sortWith . Функция сортировки определяет, какие из этих трех функций следует использовать.
List.sort использует универсальное сравнение по умолчанию. Универсальное сравнение использует глобальные операторы на основе универсальной функции сравнения значений. Он эффективно работает с широким спектром типов элементов, таких как простые числовые типы, кортежи, записи, дискриминированные объединения, списки, массивы и любой тип, реализующий System.IComparable. Для типов, реализующих System.IComparableуниверсальное сравнение, использует функцию System.IComparable.CompareTo() . Универсальное сравнение также работает со строками, но использует порядок сортировки независимо от языка и региональных параметров. Универсальное сравнение не должно использоваться для неподдерживаемых типов, таких как типы функций. Кроме того, производительность универсального сравнения по умолчанию лучше всего подходит для небольших структурированных типов; для более крупных структурированных типов, которые необходимо сравнивать и сортировать часто, рекомендуется реализовать System.IComparable и обеспечить эффективную реализацию System.IComparable.CompareTo() метода.
List.sortBy принимает функцию, которая возвращает значение, используемое в качестве критерия сортировки, и List.sortWith принимает функцию сравнения в качестве аргумента. Эти две функции полезны при работе с типами, которые не поддерживают сравнение, или если для сравнения требуется более сложная семантика сравнения, как в случае строк с поддержкой языка и региональных параметров.
В следующем примере показано использование List.sort.
let sortedList1 = List.sort [1; 4; 8; -2; 5]
printfn "%A" sortedList1
Выходные данные приведены следующим образом:
[-2; 1; 4; 5; 8]
В следующем примере показано использование List.sortBy.
let sortedList2 = List.sortBy (fun elem -> abs elem) [1; 4; 8; -2; 5]
printfn "%A" sortedList2
Выходные данные приведены следующим образом:
[1; -2; 4; 5; 8]
В следующем примере показано использование List.sortWith. В этом примере пользовательская функция compareWidgets сравнения используется для первого сравнения одного поля пользовательского типа, а затем другого, когда значения первого поля равны.
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
Выходные данные приведены следующим образом:
[{ID = 92;
Rev = 1;}; {ID = 92;
Rev = 1;}; {ID = 100;
Rev = 2;}; {ID = 100;
Rev = 5;}; {ID = 110;
Rev = 1;}]
Операции поиска в списках
Для списков поддерживаются многочисленные операции поиска. Самый простой элемент List.find позволяет найти первый элемент, соответствующий заданному условию.
В следующем примере кода показано, List.find как найти первое число, которое делится на 5 в списке.
let isDivisibleBy number elem = elem % number = 0
let result = List.find (isDivisibleBy 5) [ 1 .. 100 ]
printfn "%d " result
Результат равен 5.
Если элементы должны быть преобразованы сначала, вызов List.pick, который принимает функцию, которая возвращает параметр, и ищет первое значение параметра, которое является Some(x). Вместо возврата элемента List.pick возвращает результат x. Если соответствующий элемент не найден, List.pick вызывается исключение System.Collections.Generic.KeyNotFoundException. В следующем коде показано использование 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
Выходные данные приведены следующим образом:
"b"
Другая группа операций поиска, List.tryFind и связанные функции, возвращает значение параметра. Функция List.tryFind возвращает первый элемент списка, который удовлетворяет условию, если такой элемент существует, но значение None параметра, если нет. Вариант List.tryFindIndex возвращает индекс элемента, если он найден, а не сам элемент. Эти функции показаны в следующем коде.
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."
Выходные данные приведены следующим образом:
The first even value is 22.
The first even value is at position 8.
Арифметические операции в списках
Распространенные арифметические операции, такие как сумма и среднее значение, встроены в модуль List. Для работы с List.sum тип элемента list должен поддерживать + оператор и иметь нулевое значение. Все встроенные арифметические типы удовлетворяют этим условиям. Для работы с List.average тип элемента должен поддерживать деление без остатка, что исключает целые типы, но позволяет использовать типы с плавающей запятой. Функции List.sumBy и List.averageBy принимают функцию в качестве параметра, а результаты этой функции используются для вычисления значений суммы или среднего значения.
В следующем коде демонстрируется использование List.sum, List.sumByи 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
Результат выглядит так: 1.000000.
В следующем коде показано использование List.averageBy.
let avg2 = List.averageBy (fun elem -> float elem) [1 .. 10]
printfn "%f" avg2
Результат выглядит так: 5.5.
Списки и кортежи
Списки, содержащие кортежи, можно управлять с помощью функций ZIP и распаки. Эти функции объединяют два списка отдельных значений в один список кортежей или разделяют один список кортежей на два списка отдельных значений. Простейшая функция List.zip принимает два списка отдельных элементов и создает один список пар кортежей. Другая версия List.zip3 принимает три списка отдельных элементов и создает один список кортежей с тремя элементами. В следующем примере кода показано использование List.zip.
let list1 = [ 1; 2; 3 ]
let list2 = [ -1; -2; -3 ]
let listZip = List.zip list1 list2
printfn "%A" listZip
Выходные данные приведены следующим образом:
[(1, -1); (2, -2); (3; -3)]
В следующем примере кода показано использование List.zip3.
let list3 = [ 0; 0; 0]
let listZip3 = List.zip3 list1 list2 list3
printfn "%A" listZip3
Выходные данные приведены следующим образом:
[(1, -1, 0); (2, -2, 0); (3, -3, 0)]
Соответствующие версии unzip, List.unzip и List.unzip3, принимают списки кортежей и возвращаемых списков в кортеже, где первый список содержит все элементы, которые были первыми в каждом кортеже, а второй список содержит второй элемент каждого кортежа и т. д.
В следующем примере кода показано использование List.unzip.
let lists = List.unzip [(1,2); (3,4)]
printfn "%A" lists
printfn "%A %A" (fst lists) (snd lists)
Выходные данные приведены следующим образом:
([1; 3], [2; 4])
[1; 3] [2; 4]
В следующем примере кода показано использование List.unzip3.
let listsUnzip3 = List.unzip3 [(1,2,3); (4,5,6)]
printfn "%A" listsUnzip3
Выходные данные приведены следующим образом:
([1; 4], [2; 5], [3; 6])
Работа с элементами списка
F# поддерживает различные операции с элементами списка. Самый простой — List.iter, который позволяет вызывать функцию для каждого элемента списка. Варианты включают List.iter2, что позволяет выполнять операцию с элементами двух списков, List.iteri, которая похожа на List.iter то, что индекс каждого элемента передается в качестве аргумента функции, вызываемой для каждого элемента, и List.iteri2, которая является сочетанием функциональных возможностей List.iter2 и List.iteri. В следующем примере кода показаны эти функции.
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
Выходные данные приведены следующим образом:
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
Другая часто используемая функция, которая преобразует элементы списка— List.map, которая позволяет применять функцию к каждому элементу списка и помещать все результаты в новый список.
List.map2 и List.map3 — это варианты, которые принимают несколько списков. Кроме того, можно использовать List.mapi и List.mapi2, если в дополнение к элементу необходимо передать индекс каждого элемента. Единственное различие между и List.mapi заключается в List.mapi2 том, что List.mapi2 работает с двумя списками. В следующем примере показан Список.карта.
let list1 = [1; 2; 3]
let newList = List.map (fun x -> x + 1) list1
printfn "%A" newList
Выходные данные приведены следующим образом:
[2; 3; 4]
В следующем примере показано использование 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
Выходные данные приведены следующим образом:
[5; 7; 9]
В следующем примере показано использование List.map3.
let newList2 = List.map3 (fun x y z -> x + y + z) list1 list2 [2; 3; 4]
printfn "%A" newList2
Выходные данные приведены следующим образом:
[7; 10; 13]
В следующем примере показано использование List.mapi.
let newListAddIndex = List.mapi (fun i x -> x + i) list1
printfn "%A" newListAddIndex
Выходные данные приведены следующим образом:
[1; 3; 5]
В следующем примере показано использование List.mapi2.
let listAddTimesIndex = List.mapi2 (fun i x y -> (x + y) * i) list1 list2
printfn "%A" listAddTimesIndex
Выходные данные приведены следующим образом:
[0; 7; 18]
List.collect похож List.map, за исключением того, что каждый элемент создает список, и все эти списки объединяются в окончательный список. В следующем коде каждый элемент списка создает три числа. Все они собираются в один список.
let collectList = List.collect (fun x -> [for i in 1..3 -> x * i]) list1
printfn "%A" collectList
Выходные данные приведены следующим образом:
[1; 2; 3; 2; 4; 6; 3; 6; 9]
Можно также использовать List.filter, который принимает логическое условие и создает новый список, состоящий только из элементов, удовлетворяющих заданному условию.
let evenOnlyList = List.filter (fun x -> x % 2 = 0) [1; 2; 3; 4; 5; 6]
Результирующий список имеет значение [2; 4; 6].
Сочетание карты и фильтра , List.select позволяет одновременно преобразовывать и выбирать элементы.
List.choose Применяет функцию, возвращающую параметр к каждому элементу списка, и возвращает новый список результатов для элементов, когда функция возвращает значение Someпараметра.
В следующем коде показано, как List.choose выбрать прописные слова из списка слов.
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
Выходные данные приведены следующим образом:
["Rome's"; "Bob's"]
Работа с несколькими списками
Списки можно объединить вместе. Чтобы объединить два списка в один, используйте List.append. Чтобы присоединиться к более чем двум спискам, используйте 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
Операции свертывания и сканирования
Некоторые операции списка включают взаимозависимости между всеми элементами списка. Операции свертывания и сканирования похожи List.iter и List.map в том, что вы вызываете функцию для каждого элемента, но эти операции предоставляют дополнительный параметр, называемый накопительным элементом , который несет информацию через вычисления.
Используется List.fold для выполнения вычисления в списке.
В следующем примере кода показано использование List.fold для выполнения различных операций.
Список проходит по списку; Накопитель acc — это значение, передаваемое вместе по мере выполнения вычисления. Первый аргумент принимает накопительный элемент и элемент списка и возвращает промежуточный результат вычисления для этого элемента списка. Второй аргумент — начальное значение аккумулятора.
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])
Версии этих функций, имеющие цифру в имени функции, работают с несколькими списками. Например, List.fold2 выполняет вычисления в двух списках.
В следующем примере показано использование 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 и List.scan отличаются в том, что List.fold возвращает окончательное значение дополнительного параметра, но List.scan возвращает список промежуточных значений (а также окончательное значение) дополнительного параметра.
Каждая из этих функций включает обратный вариант, например List.foldBack, который отличается в порядке, в котором выполняется обход списка и порядок аргументов. Кроме того, List.fold и List.foldBack есть варианты List.fold2 и List.foldBack2, которые принимают два списка равной длины. Функция, которая выполняется на каждом элементе, может использовать соответствующие элементы обоих списков для выполнения некоторых действий. Типы элементов двух списков могут отличаться, как в следующем примере, в котором один список содержит суммы транзакций для банковского счета, а другой список содержит тип транзакции: депозит или вывод.
// 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
Для вычисления, например суммирования, и List.foldBack имеют тот же эффект, List.fold так как результат не зависит от порядка обхода. В следующем примере List.foldBack используется для добавления элементов в список.
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])
В следующем примере возвращается пример банковского счета. На этот раз добавляется новый тип транзакции: вычисление процентов. Конечный баланс теперь зависит от порядка транзакций.
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
Функция List.reduce несколько похожа List.foldList.scanи, за исключением того, что вместо передачи вокруг отдельного накопительного элемента List.reduce принимает функцию, которая принимает два аргумента типа элемента вместо одного, а один из этих аргументов выступает в качестве аккумулятора, что означает, что он сохраняет промежуточный результат вычисления.
List.reduce запускается с первых двух элементов списка, а затем использует результат операции вместе со следующим элементом. Так как есть не отдельный накопитель, имеющий собственный тип, можно использовать вместо List.fold того, чтобы использовать только в том случае, List.reduce если накопитель и тип элемента имеют тот же тип. В следующем коде показано использование List.reduce.
List.reduce создает исключение, если указанный список не содержит элементов.
В следующем коде первый вызов лямбда-выражения получает аргументы 2 и 4 и возвращает 6, а следующий вызов получает аргументы 6 и 10, поэтому результат равен 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
Преобразование между списками и другими типами коллекций
Модуль List предоставляет функции для преобразования в последовательности и массивы и из нее. Чтобы преобразовать в последовательность или из нее, используйте List.toSeq или List.ofSeq. Чтобы преобразовать или из массива, используйте List.toArray или List.ofArray.
Дополнительные операции
Дополнительные сведения о дополнительных операциях со списками см. в разделе " Модуль списка списков библиотеки".