Подтвердить что ты не робот

Как найти частоту символов в строке в Haskell?

Как подсчитать частоту символов в строке и затем вывести их в виде таблицы?

Например, если я ввещу слово "happy", результат будет

h 1  
a 1  
p 2  
y 1  

Если это можно заказать в порядке ASCII, это будет блестящим.

Я знаю, что мне нужно использовать функцию count, любые другие подсказки будут оценены.

РЕДАКТИРОВАТЬ: Все ответы блестящие, только я такой новичок в Haskell, что я действительно не понимаю, что они делают.

4b9b3361

Ответ 1

Простейшим решением является использование Data.Map для хранения промежуточного сопоставления от символа до частоты. Затем вы можете легко построить счетчики, используя fromListWith. Поскольку Data.Map сортируется, вы получаете их в порядке ASCII бесплатно.

λ> :m + Data.Map
λ> let input = "happy"
λ> toList $ fromListWith (+) [(c, 1) | c <- input]
[('a',1),('h',1),('p',2),('y',1)]

Итак, что здесь происходит?

Идея состоит в том, чтобы построить Data.Map (древовидную карту), используя символы как ключи и частоты как значения.

Сначала мы берем входную строку и делаем кортежи каждого символа с 1, чтобы указать одно вхождение.

λ> [(c, 1) | c <- input]
[('h',1),('a',1),('p',1),('p',1),('y',1)]

Затем мы используем fromListWith для построения сортированной карты из этих пар ключ-значение, многократно вставляя каждую пару ключ-значение в карту. Мы также предоставляем ему функцию, которая будет использоваться, когда ключ уже был на карте. В нашем случае мы используем (+), так что, когда символ отображается несколько раз, мы добавляем счет к существующей сумме.

Наконец, мы скрываем отображение обратно в список кортежей с ключом, используя toList.

Ответ 2

Вероятно, что-то короче, но это работает:

Prelude> import Data.List
Prelude Data.List> map (\x -> (head x, length x)) $ group $ sort "happy"
[('h',1),('a',1),('p',2),('y',1)]

Ответ 3

func xs = map (\a -> (head a, length a)) $ group $ sort xs

Ответ 4

Использовать список, нет необходимости в импорте или сортировке.

[ (x,c) | x<-['A'..'z'], let c = (length.filter (==x)) "happy", c>0 ]

Результат:

[('a',1),('h',1),('p',2),('y',1)]

Выше фильтруется и переписывается (только символ со счетом > 0) из:

[(x,(length.filter (==x)) "happy" ) | x<-['A'..'z']]

Пояснение:

  • Составьте список всех символов, соответствующих данному символу (A..z).
  • Для каждого символа подсчитайте этот список (== длина)
  • Поместите этот счет в кортеж с символом

Ответ 5

Я запишу шаг за шагом. Более короткое решение возможно с использованием стандартных функций.

Вы хотите отсортированный результат, поэтому

result = sort cs
    where

cs будет списком кортежей, где первым элементом является символ, а второй - количество раз, которое оно появляется.

        cs = counts "happy"
        counts [] = []
        counts (c:cs) = (c, length otherc + 1) : counts nonc where
             (otherc, nonc) = partition (c==) cs

Что все.

Интересно, что счетчик работает с любым списком элементов, поддерживающим оператор ==.

Ответ 6

import Data.Array (Ix, accumArray, assocs)

eltDist :: (Bounded a, Ix a, Eq b, Num b) => [a] -> [(a, b)]
eltDist str = filter ((/=0) . snd ) $ 
     assocs (accumArray (+) 0 (minBound, maxBound) [(i, 1) | i <- str])

"minBound" и "maxBound" будут зависеть от диапазона типа, указанного для i. Для Char это будет 0 - 1,114,111, что является экстравагантным, но не невозможным. Это было бы особенно удобно, если бы вы подсчитывали символы Unicode. Если вас интересуют только строки ASCII, то (0, 255). Хорошая вещь в массивах состоит в том, что они могут быть проиндексированы любым типом, который может быть отображен на целое число. См. Ix.

assocs вытягивает индексы и подсчитывает из массива в список пар, а фильтр удаляет неиспользуемые.