В F # возможна мутация состояния, такая как cnt[word] += 1
, но ее обычно избегают. Вместо этого вычисления выражаются с использованием функций высшего порядка для описания цели операции, а не с помощью императивных команд для описания механизма. В этом случае типичное решение F # может выглядеть примерно так:
let counts =
["red"; "blue"; "red"; "green"; "blue"; "blue"]
|> List.groupBy id
|> Map.ofList
|> Map.map (fun _ words -> words |> List.length)
Здесь мы берем тот же список слов, затем используем List.groupBy
для создания списка списков и передаем ему функцию id
, чтобы сказать, что мы хотим сгруппировать по самим значениям (словам в списке). Список слов фактически является вторым параметром List.groupBy
, но мы используем оператор |>
("pipe-forward"), чтобы передать предыдущее значение в качестве последнего параметра следующей функции. Это полезно, поскольку позволяет нам объединять операции вместе, как мы видим в следующей строке, где мы берем список списков, возвращаемых List.groupBy
, и передаем его в Map.ofList
, что дает нам Map<string, string list>
.
Тип
A Map
позволяет выполнять поиск по ключу, например, тип Counter
. Затем мы преобразуем Map<string, string list>
в Map<string, int>
с количеством каждого слова, передавая результат Map.ofList
в Map.map
, что позволяет нам передавать функцию, которая преобразует значения в карте из одного типа в другой. В этом случае мы хотим преобразовать значения из string list
в int
, поэтому мы берем string list
(который мы будем называть «словами») и передаем его в List.length
, чтобы получить счетчик. Параметр функции для Map.map
принимает два параметра, ключ и значения, но нас интересуют только значения, поэтому я проигнорировал параметр ключа, вызвав его _
. Это дает нам Map<string, int>
, который содержит слово в качестве ключа и счетчик этого слова в списке в качестве значения:
val counts : Map<string,int> = map [("blue", 3); ("green", 1); ("red", 2)]
EDIT
Как упомянуто в комментариях kvb, модуль F # List
уже имеет функцию countBy
, которая комбинирует groupBy
с List.length
для вас. Это делает код еще проще:
let counts =
["red"; "blue"; "red"; "green"; "blue"; "blue"]
|> List.countBy id
|> Map.ofList
Это дает тот же результат, что и выше, потому что мы берем список string * int
кортежей и передаем его в Map.ofList
, чтобы получить возможности поиска карты (например, объекта Python Counter
).