Привет, читатель, я вернулся с еще одним эпизодом из этой серии, где мы выбираем одну проблему и рассматриваем несколько решений, написанных на разных языках программирования.

Чтобы прочитать две предыдущие статьи, нажмите :
здесьдля популярных решений
и здесь
для палиндромарешения

После надлежащего введения давайте сначала разберемся с проблемой. Частоты — это распространенное понятие, используемое в основном в статистике и ее производных, таких как наука о данных и машинное обучение, и в основном оно состоит из группировки значений по количеству, которое они появлялись, например:

если мы хотим рассчитать возраст определенного населения

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, а также использование анонимной функции на этапе сокращения.

И это одна проблема, еще пять решений, третий эпизод доставлен, спасибо, что дочитали до сюда, надеюсь увидеть вас в моей следующей статье.

До встречи!