sig*_*ign 25 string haskell split
我试图在Haskell中编写程序,它将使用逗号分隔的整数数字串,将其转换为整数列表并将每个数字递增1.
例如
"1,2,-5,-23,15" -> [2,3,-4,-22,16]
以下是生成的程序
import Data.List
main :: IO ()
main = do
n <- return 1
putStrLn . show . map (+1) . map toInt . splitByDelimiter delimiter
$ getList n
getList :: Int -> String
getList n = foldr (++) [] . intersperse [delimiter] $ replicate n inputStr
delimiter = ','
inputStr = "1,2,-5,-23,15"
splitByDelimiter :: Char -> String -> [String]
splitByDelimiter _ "" = []
splitByDelimiter delimiter list =
map (takeWhile (/= delimiter) . tail)
(filter (isPrefixOf [delimiter])
(tails
(delimiter : list)))
toInt :: String -> Int
toInt = read
Run Code Online (Sandbox Code Playgroud)
对我来说最困难的部分是对函数进行编程,该函数splitByDelimiter采用String并返回字符串列表
"1,2,-5,-23,15" -> ["1","2","-5","-23","15"]
认为它有效,我对它的编写方式不满意.有很多括号,所以它看起来像Lisp.算法也有点人为:
将分隔符预先添加到字符串的开头 ",1,2,-5,-23,15"
生成所有尾部的列表 [",1,2,-5,-23,15", "1,2,-5,-23,15", ",2,-5,-23,15", .... ]
过滤并仅保留以分隔符开头的字符串 [",1,2,-5,-23,15", ",2,-5,-23,15", .... ]
删除第一个分隔符并取符号,直到满足下一个分隔符 ["1", "2", .... ]
所以问题是:
我怎样才能改善功能splitByDelimiter?
我可以删除前缀和分隔符并直接拆分字符串吗?
我如何重写函数,以便括号更少?
可能是我想念一下这个功能已经有标准功能吗?
Sat*_*vik 23
splitBy delimiter = foldr f [[]]
where f c l@(x:xs) | c == delimiter = []:l
| otherwise = (c:x):xs
Run Code Online (Sandbox Code Playgroud)
编辑:不是由原作者,但下面是一个更多(过度?)冗长,不太灵活的版本(特定于Char/ String),以帮助澄清这是如何工作的.使用上面的版本,因为它适用于具有Eq实例的任何类型的列表.
splitBy :: Char -> String -> [String]
splitBy _ "" = [];
splitBy delimiterChar inputString = foldr f [""] inputString
where f :: Char -> [String] -> [String]
f currentChar allStrings@(partialString:handledStrings)
| currentChar == delimiterChar = "":allStrings -- start a new partial string at the head of the list of all strings
| otherwise = (currentChar:partialString):handledStrings -- add the current char to the partial string
-- input: "a,b,c"
-- fold steps:
-- first step: 'c' -> [""] -> ["c"]
-- second step: ',' -> ["c"] -> ["","c"]
-- third step: 'b' -> ["","c"] -> ["b","c"]
-- fourth step: ',' -> ["b","c"] -> ["","b","c"]
-- fifth step: 'a' -> ["","b","c"] -> ["a","b","c"]
Run Code Online (Sandbox Code Playgroud)
Has*_*ant 11
这有点像黑客,但是,它确实有效.
yourFunc str = map (+1) $ read ("[" ++ str ++ "]")
Run Code Online (Sandbox Code Playgroud)
这是一个非黑客版本使用unfoldr:
import Data.List
import Control.Arrow(second)
-- break' is like break but removes the
-- delimiter from the rest string
break' d = second (drop 1) . break d
split :: String -> Maybe (String,String)
split [] = Nothing
split xs = Just . break' (==',') $ xs
yourFunc :: String -> [Int]
yourFunc = map ((+1) . read) . unfoldr split
Run Code Online (Sandbox Code Playgroud)
只是为了好玩,以下是如何使用Parsec创建一个简单的解析器:
module Main where
import Control.Applicative hiding (many)
import Text.Parsec
import Text.Parsec.String
line :: Parser [Int]
line = number `sepBy` (char ',' *> spaces)
number = read <$> many digit
Run Code Online (Sandbox Code Playgroud)
一个优点是它可以轻松创建一个灵活的解析器:
*Main Text.Parsec Text.Parsec.Token> :load "/home/mikste/programming/Temp.hs"
[1 of 1] Compiling Main ( /home/mikste/programming/Temp.hs, interpreted )
Ok, modules loaded: Main.
*Main Text.Parsec Text.Parsec.Token> parse line "" "1, 2, 3"
Right [1,2,3]
*Main Text.Parsec Text.Parsec.Token> parse line "" "10,2703, 5, 3"
Right [10,2703,5,3]
*Main Text.Parsec Text.Parsec.Token>
Run Code Online (Sandbox Code Playgroud)