字符串到多集 haskell
string to multi set haskell
将字符串转换为多重集,如下例:
"bacaba" --> [(b,2),(a,3),(c,1)]
type MSet a = [(a,Int)]
convert :: Eq a => [a] -> MSet
我的代码有什么问题,更好的方法是什么?泰
convert :: Eq a => [a] -> MSet a
convert [] = []
convert (x:xs) = ((x,1+count x xs) : converte xs)
where count x [] = 0
count x (y:ys) = if (x == y) then 1 + count x ys else count x ys
你快到了。
问题出在您对 convert
函数的递归调用上。由于您已经计算了特定字符的字符数,因此不需要再次计算它们。只需使用 filter
函数在调用 convert
:
时删除该字符
convert :: Eq a => [a] -> MSet a
convert [] = []
convert (x:xs) = (x,1+count x xs) : convert (filter (\y -> y /= x) xs)
where count x [] = 0
count x (y:ys) = if (x == y) then 1 + count x ys else count x ys
或者写得更简洁:
convert :: Eq a => [a] -> MSet a
convert [] = []
convert (x:xs) = (x,1+count x xs) : convert (filter (/= x) xs)
where count x [] = 0
count x (y:ys) = if (x == y) then 1 + count x ys else count x ys
ghci 中的演示:
ghci| > convert "bacaba"
[('b',2),('a',3),('c',1)]
what is the better way to do it?
您的代码执行 O(n^2)
;如果类型是 Ord
类型 class 的实例(如您的示例所示),使用 Data.Map
您可能会获得 O(n log n)
性能:
import Data.Map (toList, fromListWith)
convert :: (Ord a) => [a] -> [(a, Int)]
convert xs = toList . fromListWith (+) . zip xs $ repeat 1
这将导致正确的计数,但列表将按以下键排序:
\> convert "bacaba"
[('a',3),('b',2),('c',1)]
如果需要保留顺序,则
import qualified Data.Map as M
import Data.Map (delete, fromListWith)
convert :: (Ord a) => [a] -> [(a, Int)]
convert xs = foldr go (const []) xs . fromListWith (+) . zip xs $ repeat 1
where
go x f cnt = case M.lookup x cnt of
Just i -> (x, i): f (x `delete` cnt)
Nothing -> f cnt
这将输出:
\> convert "bacaba"
[('b',2),('a',3),('c',1)]
将字符串转换为多重集,如下例:
"bacaba" --> [(b,2),(a,3),(c,1)]
type MSet a = [(a,Int)]
convert :: Eq a => [a] -> MSet
我的代码有什么问题,更好的方法是什么?泰
convert :: Eq a => [a] -> MSet a
convert [] = []
convert (x:xs) = ((x,1+count x xs) : converte xs)
where count x [] = 0
count x (y:ys) = if (x == y) then 1 + count x ys else count x ys
你快到了。
问题出在您对 convert
函数的递归调用上。由于您已经计算了特定字符的字符数,因此不需要再次计算它们。只需使用 filter
函数在调用 convert
:
convert :: Eq a => [a] -> MSet a
convert [] = []
convert (x:xs) = (x,1+count x xs) : convert (filter (\y -> y /= x) xs)
where count x [] = 0
count x (y:ys) = if (x == y) then 1 + count x ys else count x ys
或者写得更简洁:
convert :: Eq a => [a] -> MSet a
convert [] = []
convert (x:xs) = (x,1+count x xs) : convert (filter (/= x) xs)
where count x [] = 0
count x (y:ys) = if (x == y) then 1 + count x ys else count x ys
ghci 中的演示:
ghci| > convert "bacaba"
[('b',2),('a',3),('c',1)]
what is the better way to do it?
您的代码执行 O(n^2)
;如果类型是 Ord
类型 class 的实例(如您的示例所示),使用 Data.Map
您可能会获得 O(n log n)
性能:
import Data.Map (toList, fromListWith)
convert :: (Ord a) => [a] -> [(a, Int)]
convert xs = toList . fromListWith (+) . zip xs $ repeat 1
这将导致正确的计数,但列表将按以下键排序:
\> convert "bacaba"
[('a',3),('b',2),('c',1)]
如果需要保留顺序,则
import qualified Data.Map as M
import Data.Map (delete, fromListWith)
convert :: (Ord a) => [a] -> [(a, Int)]
convert xs = foldr go (const []) xs . fromListWith (+) . zip xs $ repeat 1
where
go x f cnt = case M.lookup x cnt of
Just i -> (x, i): f (x `delete` cnt)
Nothing -> f cnt
这将输出:
\> convert "bacaba"
[('b',2),('a',3),('c',1)]