我正在尝试创建一个从字符串中删除每个第n个元素的函数。
dropEvery :: String -> Int -> String
dropEvery str n = map (\(char, indx) -> if indx `mod` n /= 0 then char else ' ') (zip str [1..])
现在它只是用空格替换每个第n个元素,但如果我希望它返回“空字符”,我应该在“else”之后放置什么。我知道在Haskell中不存在这样的事情,所以问题是 - 我怎么能告诉Haskell不返回任何东西而只是转到下一个字符?
答案 0 :(得分:7)
您不能仅使用map
来执行此操作,根据定义,它无法更改应用它的集合的长度。但是,通过切换到concatMap
,您无需进行太多更改即可实现此功能。此函数需要您正在映射的函数返回一个列表,然后将所有结果连接在一起。所有你需要做的是
dropEvery str n =
concatMap (\(char, indx) -> if indx `mod` n /= 0 then [char] else []) (zip str [1..])
答案 1 :(得分:5)
MainActivity
保留列表的结构,而您的操作通过删除元素来修改它。这意味着您无法使用map
,但您可以使用map
,它允许您为要从输出中删除的元素提供返回mapMaybe
的函数:
Nothing
答案 2 :(得分:3)
您可以在不mod
的情况下执行此操作。我要翻转参数的顺序,使其更加惯用。
dropEvery :: Int -> [a] -> [a]
dropEvery n xs = map fst . filter ((/= n) . snd) $ zip xs (cycle [1..n])
如果速度至关重要,那么将此技术用于显式递归或foldr
可能是最有效的。像这样:
dropEvery n xs = foldr go (`seq` []) xs n where
go _ r 1 = r n
go x r k = x : r (k - 1)