How can I write a function in Haskell, that takes an input string in the format a1a2a3 and expands into a1a2a2a3a3a3. For example input string "code" would be expanded into "coodddeeee"
+14
A:
So you want the nth
character repeated n
times.
f :: String -> String
f x = concatMap g (zip x [1..])
where
g (x,y) = replicate y x
I'm sure there's an easier way to do this.
Explanation: First we get the string and pair it with it's place in the list (starting at 1). This is what zip does:
Prelude> zip "code" [1..]
[('c',1),('o',2),('d',3),('e',4)]
Now the function g (x,y)
uses the replicate function which replicates whatever you want y times. So we replicate x, y times.
Prelude> g ('z',4)
"zzzz"
If we map this function over the list produced you get the result:
Prelude> map g $ zip "code" [1..]
["c","oo","ddd","eeee"]
If you have a list of strings, you can concatenate them together using concat
. concatMap
applies the function g
to each pair of letter and number and then concatenates the string into the final result.
Prelude> concat $ map g $ zip "code" [1..]
"coodddeeee"
Basically: concat $ map g
-> concatMap g
EDIT: now it works, it can also be done in one line thusly:
f x = concatMap (\(a,b)->replicate b a ) $ zip x [1..]
Output:
Prelude> f "lambda"
"laammmbbbbdddddaaaaaa"
Jonno_FTW
2010-01-24 11:38:00
Jonno... Could you explain that answer, As someone who is in the very early stages of learning haskell, the above answer just does not make sense to me.
BM
2010-01-24 11:47:14
See the edit for explanation
Jonno_FTW
2010-01-24 11:51:42
I'd replace `g` with `uncurry . flip replicate`. Does the same thing, but uses standard Haskell library functions.
me_and
2010-01-24 12:22:33
I don't think this person would understand currying at this point in learning Haskell.
Jonno_FTW
2010-01-24 12:27:05
Jonno... Thanks for the detailed explanation,However I chose another answer, because the simplicity of that answer appealed to me
BM
2010-01-24 12:38:09
Short version: `f = concat . zipWith replicate [1..]`
sdcvvc
2010-01-24 12:44:12
Or if you (*cough*) happen to have a string of length > maxBound::Int, then you could use genericReplicate...
trinithis
2010-01-24 21:52:08
sdcvvc should post his comment as an answer -- it is really the clearest way to me.
MtnViewMark
2010-01-24 23:55:07
trinithis: If you have a string of length == maxBound::Int on a 32-bit machine, the result of applying this function to that string will be 1 + 2 + 3 + ... + 2147483647 = 2305843 terabytes - assuming 1 byte per character and ignoring the list overhead. Luckily Haskell is lazy so you probably won't need to allocate it all at once, although you'll still be waiting a long time just to walk to the end :-)
Nefrubyr
2010-01-25 10:29:24
+7
A:
Probably very inefficient :)
f :: Int -> [Char] -> [Char]
f _ [] = []
f n (c:s) = (replicate n c) ++ (f (n+1) s)
g :: [Char] -> [Char]
g s = f 1 s
.
*Main> g "code"
"coodddeeee"
KennyTM
2010-01-24 11:43:31
FYI: juxtaposition binds more tightly than anything but @, so you can remove a few overly paranoid parentheses. f n (c:s) = replicate n c ++ f (n+1) s
Edward Kmett
2010-01-24 23:45:01
+9
A:
import Control.Monad
f = zip [1..] >=> uncurry replicate
yields
Main> f "code"
"coodddeeee"
Edward Kmett
2010-01-24 23:42:18
Nice! For those people like me, who don't know the type of the operator: "Left-to-right Kleisli composition of monads: `(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)`"
Tom Lokhorst
2010-01-25 08:26:28