What is the best way to split a string by a delimiter functionally?
Doesn't Data.List.Split.splitOn do this?
This is a bit of a hack, but heck, it works.
yourFunc str = map (+1) $ read ("[" ++ str ++ "]")
Here is a non-hack version using 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
splitBy delimiter = foldr f [[]]
where f c l@(x:xs) | c == delimiter = []:l
| otherwise = (c:x):xs
Edit: not by the original author, but below is a more (overly?) verbose, and less flexible version (specific to Char
/String
) to help clarify how this works. Use the above version because it works on any list of a type with an Eq
instance.
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"]