Reputation: 334
Hi I am trying to implement a simple function that does this with list comprehension:
duplicate "asdf" = "assdff"
duplicate "123456" = "122344566"
and this is what I came up with
duplicate xs =
[ y | x <- xs
, i <- [0..]
, y <- if i `mod` 2 == 0
then replicate 2 x
else x ]
I wanted i to act as a counter to keep track of the position of the list, and x to hold the list.
Is there a way to make this work?
Upvotes: 1
Views: 653
Reputation: 52280
The reason yours is not working is that your else
branch does not produce an list inside your function - you can easily fix the syntax issue like this:
duplicate xs =
[ y | x <- xs
, i <- [0..]
, y <- if i `mod` 2 == 0
then replicate 2 x
else [x] ]
but this would give you nothing but an endless list of the first thing in xs
(because there are infinite many i
s)
Now my guess is that you indeed want to replicate every other element 2 times and yes zip
is a great idea and you are almost there (with your comment):
just make sure that you fix the syntax/type error there as well:
duplicate xs =
[ y | (i, x) <- zip [0..] xs
, y <- if i `mod` 2 == 0
then replicate 2 x
else [x] ]
this will give you:
λ> duplicate "Hello"
"HHellloo"
which is hopefully what you are looking for
You can rewrite this into
duplicate = concat . zipWith replicate (cycle [2, 1])
try to find out how this works
Hint: it's based on the idea of: take 2 of the first, then 1 of the second, then 2 of the third, then 1 of the forth, ... - only obfuscated by Haskells higher-order function and operator zoo ;)
Upvotes: 4
Reputation: 8866
You can use zip to provide items with indexes:
Prelude> zip "asdf" [0..]
[('a',0),('s',1),('d',2),('f',3)]
Upvotes: 3