views:

453

answers:

3

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
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
See the edit for explanation
Jonno_FTW
I'd replace `g` with `uncurry . flip replicate`. Does the same thing, but uses standard Haskell library functions.
me_and
I don't think this person would understand currying at this point in learning Haskell.
Jonno_FTW
Jonno... Thanks for the detailed explanation,However I chose another answer, because the simplicity of that answer appealed to me
BM
Short version: `f = concat . zipWith replicate [1..]`
sdcvvc
Or if you (*cough*) happen to have a string of length > maxBound::Int, then you could use genericReplicate...
trinithis
sdcvvc should post his comment as an answer -- it is really the clearest way to me.
MtnViewMark
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
+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
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
+9  A: 
import Control.Monad
f = zip [1..] >=> uncurry replicate

yields

Main> f "code"
"coodddeeee"
Edward Kmett
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