Haskell 枚举值的计数频率
假设我有一个像Haskell 枚举值的计数频率,haskell,enums,Haskell,Enums,假设我有一个像 data T = A | B | C deriving (Enum) 以及作为输入的枚举值列表: [B, C, C, A, C, A, C] 我要找的是一个函数,给定这个输入,它返回每个元素在输入中出现的频率。输出的简单形式是频率列表(在本例中为[2,1,4]),但这不是要求。我目前的做法如下: countEnum :: Enum a => [a] -> [a] -> [Word] countEnum elems = let f x = map (fr
data T = A | B | C deriving (Enum)
以及作为输入的枚举值列表:
[B, C, C, A, C, A, C]
我要找的是一个函数,给定这个输入,它返回每个元素在输入中出现的频率。输出的简单形式是频率列表(在本例中为[2,1,4]
),但这不是要求。我目前的做法如下:
countEnum :: Enum a => [a] -> [a] -> [Word]
countEnum elems =
let f x = map (fromIntegral . fromEnum . (fromEnum x ==)) [0 .. length elems - 1]
in foldr (zipWith (+)) (replicate (length elems) 0) . map f
这是可行的,但我至少看到两个问题:
length
功能有什么办法可以改进吗?也许是这样的
import Control.Arrow ((&&&))
import Data.Function (on)
import Data.List (groupBy, sortBy)
data T = A | B | C deriving Enum
countEnum :: Enum a => [a] -> [Int]
countEnum = map length . groupBy ((==) `on` snd) . sortBy (compare `on` snd) . map (id &&& fromEnum)
例如:
> countEnum [B, C, C, A, C, A, C]
[2,1,4]
如果您可以为T
定义一个Bounded
实例,则有可能计算零次出现:
countEnum' :: (Bounded a, Enum a) => [a] -> [Int]
countEnum' = map pred . countEnum . (++ enumFromTo minBound maxBound)
> countEnum' [C, C, A, C, A, C]
[2,0,4]
通常使用
映射比排序列表快一点
enumFreq :: Enum a => [a] -> Map Int Word
enumFreq = foldl' (\mp e -> Map.insertWith' (+) (fromEnum e) 1 mp) Map.empty
你可以得到
- 仅根据
Map.elems$enumFreq列表列出频率
- 成对的
(值、频率)
每[(toEnum i,f)|(i,f)如果您有Ord
,您可以使用
import Control.List
import Control.Arrow
map (head &&& length) $ group $ sort elems
类型声明是否错误?为什么countEnum
需要两个输入?@is7s:第一个参数是一个包含所有可能值的列表(主要是为了找出有多少个值)。这看起来很不错,但是如果不是所有可能的元素都出现在输入列表中,它就不起作用了(结果列表中的对应元素被省略,它应该是零)。@Philipp我认为如果没有Bounded
实例或初始示例中的显式参数,这是不可能的。enumFromTo minBound maxBound
可以写成[minBound..maxBound]
谢谢,这正是我所需要的。同时,我发现了一个基于Map
的类似解决方案,但你的更简洁。
import Control.List
import Control.Arrow
map (head &&& length) $ group $ sort elems