Как найти частоту символов в строке в Haskell?
Как подсчитать частоту символов в строке и затем вывести их в виде таблицы?
Например, если я ввещу слово "happy", результат будет
h 1
a 1
p 2
y 1
Если это можно заказать в порядке ASCII, это будет блестящим.
Я знаю, что мне нужно использовать функцию count, любые другие подсказки будут оценены.
РЕДАКТИРОВАТЬ: Все ответы блестящие, только я такой новичок в Haskell, что я действительно не понимаю, что они делают.
Ответы
Ответ 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 вытягивает индексы и подсчитывает из массива в список пар, а фильтр удаляет неиспользуемые.