Привет, читатель, я вернулся с еще одним эпизодом из этой серии, где мы выбираем одну проблему и рассматриваем несколько решений, написанных на разных языках программирования.
Чтобы прочитать две предыдущие статьи, нажмите :
— здесьдля популярных решений
— и здесь для палиндромарешения
После надлежащего введения давайте сначала разберемся с проблемой. Частоты — это распространенное понятие, используемое в основном в статистике и ее производных, таких как наука о данных и машинное обучение, и в основном оно состоит из группировки значений по количеству, которое они появлялись, например:
если мы хотим рассчитать возраст определенного населения
ages = [12,5,21,48,84,22,21,29,30,12, 21]
Если мы применим функцию частот, мы получим следующие результаты:
frequencies ages | age | amount of people with that age| | 12 | 2 | 5 | 1 | 21 | 3 | 48 | 1 | 84 | 1 | 22 | 1 | 29 | 1 | 30 | 1
Это простой, но довольно эффективный способ рассуждать о ваших данных, поэтому давайте реализуем функцию частот с нуля и сравним несколько решений.
Первое решение
Первое решение — это решение на python, python — это очень простой разработанный язык, и решение кажется очень понятным, просто взглянув на код, вы можете рассуждать о том, что происходит, единственное наблюдение, которое я бы сделал, это то, что решение имеет изменяемые состояния, которые могут вызывают побочные эффекты:
def frequencies(arr): freq = {} for v in arr: if freq.get(v): freq[v] = freq[v]+1 continue freq[v] = 1 return freq
Решение очень минималистично: одна функция, один dict, один цикл и один if, мы зацикливаем массив за время O (n), проверяя, существует ли возраст в freq dict, если нет, мы добавляем его со значением один, потому что мы нашли одного человека с таким возрастом, иначе мы просто получим количество людей и добавим еще одного.
Второе решение
Второе решение — это версия PHP, эта версия также написана на императивном C-подобном интерпретируемом языке, поэтому процесс решения будет очень похожим.
function frequencies($arr) { $freq = []; foreach ($arr as &$value) { if ($freq[$value]) { $freq[$value] = $freq[$value]+1; continue; } $freq[$value] = 1; } return $freq; }
Как видите, в нем используются те же структуры, что и в решении на Python, за исключением того, что вместо dict массив PHP также работает как тип словаря. Вы также можете заметить, что решение PHP более подробное и не такое красивое из-за некоторые символы «$», «;», «{» и «}».
Кроме того, решение PHP, к сожалению, имеет те же проблемы с изменчивостью, что и решение Python.
Третье решение
Третье решение также представляет собой C-подобный интерпретируемый язык, но в нем используется другой и более функциональный подход. Третье решение написано на JavaScript и выглядит так:
const freq = ls => ls.reduce((acc, elem) => { if (acc[elem]) { acc[elem] = acc[elem]+1 } else { acc[elem] = 1 } return acc }, {})
Наконец, в более функциональном стиле, я был очень доволен решением JavaScript, потому что это было первое неизменяемое решение в этой статье, которое действительно казалось естественным быть неизменяемым с помощью функции сокращения.
Четвертое решение
Четвертое решение — это скомпилированный системный язык, V — это язык, похожий на GO, который использует современный дизайн с автоматическим освобождением, и решение выглядит следующим образом:
fn freq(arr []int) map[int]int { mut m := map[int]int{} for v in arr{ if m[v] > 0 { m[v] = m[v]+1 continue } m[v] = 1 } return m }
V не имеет функции сокращения (после прочтения комментариев в этой статье я узнал, что V имеет эквивалентную функцию сокращения), поэтому нам пришлось использовать подход создания карты/слова и пройти через массив с циклом и если первые два решения, но мне очень понравилось решение V, потому что для типизированного языка лаконичность и простота действительно выдающиеся.
Пятое решение
Последнее решение — единственное, сделанное на функциональном языке, точнее на языке Elixir, который также использует сокращение для получения неизменяемого решения.
defmodule Freq do def freq(ls) do Enum.reduce(ls, %{}, fn elem, acc -> check_freq(elem, acc) end) end def check_freq(key, map) do value = Map.get(map, key, nil) case value do nil -> Map.put_new(map, key, 1) _ -> Map.put(map, key, value+1) end end end
Основным отличием этого решения является использование сопоставления case и шаблона вместо подхода if и else, а также использование анонимной функции на этапе сокращения.
И это одна проблема, еще пять решений, третий эпизод доставлен, спасибо, что дочитали до сюда, надеюсь увидеть вас в моей следующей статье.
До встречи!