Есть ли F # эквивалент коллекции счетчиков Python? - PullRequest
0 голосов
/ 04 сентября 2018

Нужно перенести некоторый код Python на F #. Я новичок в обоих языках. В коде Python используется коллекция «Counter», в которой элементы хранятся в виде словарных ключей, а их счетчики хранятся в виде значений словаря ». Например, в Python:

cnt = Counter()

for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']
   cnt[word] += 1

cnt
Counter({'blue': 3, 'red': 2, 'green': 1})

>> # Tally occurrences of words in a list
>> cnt = Counter()

>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:

>> ... cnt[word] += 1

>> cnt

>> Counter({'blue': 3, 'red': 2, 'green': 1})

Есть ли F # эквивалент коллекции счетчиков Python?

1 Ответ

0 голосов
/ 04 сентября 2018

В 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).

...