我必须用该元素的出现次数替换列表中的所有元素,例如如果我使用“泰勒·斯威夫特”,结果将为[1,1,1,1,1,1,1,1, 1,1,1,1]。
我已经制作了代码来计算出现次数,我只知道如何用我已经尝试过的出现次数替换所有元素:
ocurr :: [Char] -> Char -> Int
ocurr xs x = length(filter (x==) xs)
frequencias :: [Char] -> [Char]
frequencias "" = []
frequencias xs = [ ocurr xs y| y <- xs]
和
ocurr :: [Char] -> Char -> Int
ocurr xs x = length(filter (x==) xs)
frequencias :: [Char] -> [Char]
frequencias "" = []
frequencias xs = [x | y <- xs x = ocurr xs x]
但是这些都不起作用... 有人可以帮我吗?
答案 0 :(得分:5)
这不起作用,因为您在frequencias
中指定的返回类型为[Char]
,而根据您的occurr
函数,频率为Int
。空列表的特殊子句不是必需的(尽管没有错)。因此,您可以使用:
frequencias :: [Char] -> [Int]
frequencias xs = [ ocurr xs y | y <- xs ]
您还可以使用简单的map :: (a -> b) -> [a] -> [b]
:
frequencias :: [Char] -> [Int]
frequencias xs = map (ocurr xs) xs
因此,这给了我们
Prelude> frequencias "Taylor Swift"
[1,1,1,1,1,1,1,1,1,1,1,1]
Prelude> frequencias "taylor swift"
[2,1,1,1,1,1,1,1,1,1,1,2]
答案 1 :(得分:2)
所有这些过滤可能会变得昂贵。这是一个简单的解决方法:
import qualified Data.IntMap.Strict as M
import Data.IntMap.Strict (IntMap)
import Data.Char (ord)
import Control.DeepSeq (force)
import Data.List (foldl')
frequencias :: [Char] -> [Int]
frequencias xs = force res
where
freq_map :: IntMap Int
freq_map = foldl' go M.empty xs
go fm c = M.insertWith (+) (ord c) 1 fm
res = map (\c -> case M.lookup (ord c) freq_map of
Just freq -> freq
Nothing -> error "impossible") xs
force
确保可以立即对频率图进行垃圾回收;如果结果被立即消耗掉,这是不必要的,或者可能是不可取的。
防止内存泄漏的另一种方法是删除不再需要的密钥:
import qualified Data.IntMap.Strict as M
import Data.IntMap.Strict (IntMap)
import Data.Char (ord)
import Data.List (foldl')
data Blob = Blob
{ total_count :: !Int
, remaining :: !Int
}
frequencias :: [Char] -> [Int]
frequencias xs0 = finish xs0 freq_map0
where
freq_map0 :: IntMap Blob
freq_map0 = foldl' go M.empty xs0
go fm c = M.alter f (ord c) fm
where
f Nothing = Just (Blob 1 1)
f (Just (Blob x _)) = Just (Blob (x + 1) (x + 1))
finish [] _ = []
finish (c : cs) freq_map = case M.updateLookupWithKey (\_ (Blob tot remn) ->
if remn == 1
then Nothing
else Just (Blob tot (remn - 1))) (ord c) freq_map of
(Nothing, _) -> error "Whoopsy"
(Just (Blob tot _), freq_map') -> tot : finish cs freq_map'
答案 2 :(得分:0)
为了与@dfeuer的答案进行比较,这里有一些较低技术的方法。
暴力法。对于输入列表长度O(n^2)
,这具有n
的时间复杂度。
occurrences :: Eq a => [a] -> [Int]
occurrences xss = map (\ x -> count (== x) xss) xss
count :: (a -> Bool) -> [a] -> Int
count _ [] = 0
count p (x : xs) | p x = 1 + count p xs
| otherwise = count p xs
(我在功能中使用英文名称;-) count
完成了O.P.的ocurr
的工作。但是,我已将args的顺序切换为看起来更像Prelude.filter
。 ocurr
效率不高,因为filter
建立了一个中间结果作为length
的参数。我们不需要构建它:只需计算有多少元素满足谓词(== x)
。
(我很惊讶还没有Prelude.count
和Data.List.count
。)
这是低效的,因为它遍历了每个元素的列表,即使它已经“知道”该元素值的计数了-即,因为它早已在列表中遇到了该元素。
OTOH,如果大部分元素仅发生一次,则可以避免构建某种查找结构的开销。
这是使用中间缓存的版本-但仅适用于已知发生多次的元素。任何人都想猜测它的时间复杂度是什么?
data Cache3 a = TheList3 [a] | Cached3 a Int (Cache3 a)
count3 :: (a -> Bool) -> Cache3 a -> (Int, Bool)
-- return both the count and whether it was cached
count3 p (TheList3 xss) = ( count p xss, False) -- reuse count from sol'n 1
count3 p (Cached3 x c xs) | p x = (c, True)
| otherwise = count3 p xs
-- don't cache if count = 1: we've just counted its only appearance so won't need it again
occurrences3 :: Eq a => [a] -> [Int]
occurrences3 xss = go (TheList3 xss) xss where
go _ [] = []
go cc (x: xs) = c: go (if cached || c < 2 then cc else ( Cached3 x c cc)) xs where
(c, cached) = count3 (== x) cc