嗨,伙计们,我正在寻找一个函数
expand :: String -> [(Char,Int)]
这需要一串字符和数字,如"a5b3c2"
,并将其更改为字符串的配对列表,如"[('a',5),('b',3),('c',2)]"
相同的形式。
例:
expand "a5b4c2"
[('a',5),('b',4),('c',2)]
expand "d9d3"
[('d',9),('d',3)]
我已经做了一个与上述相反的函数,我要做的就是弄清楚如何做相反的事情。例:
flatten :: [(Char, Int)] -> String
flatten [] = []
flatten ((ca,cb):cs) = ca:(show cb ++ flatten cs)
这样可以吗?
import Data.List (intersperse)
import Data.List.Split (splitPlaces, wordsBy)
mystring = "a5b2c3'
>>> map ([x,y] -> (head x, read y :: Int)) $ splitPlaces (replicate (length mystring `div` 2) 2) $ wordsBy (==',') $ intersperse ',' mystring
[('a',5),('b',2),('c',3)]
更简单,这要归功于@4castle:
import Data.List (intersperse)
import Data.List.Split (chunksOf, wordsBy)
map ([x,y] -> (head x, read y :: Int)) $ chunksOf 2 $ wordsBy (==',') $ intersperse ',' mystring
更简单,仍然要归功于@4castle:
import Data.List.Split (chunksOf)
map ([x,y] -> (x, read [y] :: Int)) $ chunksOf 2 mystring
使用像 Parsec
这样的解析库。学习曲线有点陡峭(我什至不确定这是一个很好的例子(,但你可以描述解析器,就像这样的代码很少。
import qualified Text.Parsec as T
parseDigit :: T.Parsec String () Int
parseDigit = fmap (read . pure) T.digit
myParser = T.many ((,) <$> T.letter <*> parseDigit)
然后
> T.parse myParser "" "a5b4c2"
Right [('a', 5),('b',4),('c',2)]
因此,您的expand
可以定义为
import Data.Either
expand :: String -> [(Char, Int)]
expand s = fromRight [] (T.parse myParser "" s)
在分析器对输入字符串失败时返回空列表。
无需任何复杂的导入,假设交替使用字符和(个(数字,您可以使用简单的递归:
f :: [(Char, Int)] -> String
f (c:d:xs) = (c,read [d]):f xs
f x = x
一个相对简单的解决方案:
import Data.Char (digitToInt)
expand :: String -> [(Char, Int)]
expand (x:x':xs) = (x, digitToInt x'):expand xs
expand _ = []
同样,我更喜欢列表推导和/或尾递归函数。如果函数不是折叠,则返回一个列表。列表推导式返回列表。
let l = "a5b3c2"
[ (a,(read [b] :: Int)) | (a,b) <- zip l (tail l), elem b "1234567890"]
[("a",5(,("b",3(,("c",2(]
当我发布这个时,我不知道chunksOf
功能。 chunksOf
是一个非常方便的功能,我已经经常使用它了。另外,我认为我喜欢ord
函数而不是read
函数。当你有对时,你知道事情在哪里,并可以相应地处理。
[ (a,(ord b)-48) | (a:b:c) <- chunksOf 2 "a5b4c3"]