Reputation: 117
I want to repeat each successive character in the input string one more than the previous character ,starting with a single occurrence of the first character:
for example
rep "abcd" == "abbcccdddd"
I did this code for ,but this don't work for String
but produces the correct result for Int
and Char
.
rep [] =[]
rep (x:xs) =[ (x:xs)!!y| y<-[0..(length xs)] , _<- [1..y+1]]
How can I fix this?
Upvotes: 2
Views: 130
Reputation: 101959
You could first zip
the list [1..]
with your list, then apply replicate
and concat
the results:
rep xs = concatMap (uncurry replicate) $ zip [1..] xs
Example run:
Prelude> let rep xs = concatMap (uncurry replicate) $ zip [1..] xs
Prelude> rep "abcd"
"abbcccdddd"
The idea is simple, we associate to every element the number of times it should be repeated.
The zip
function has type [a] -> [b] -> [(a, b)]
, so it takes two lists and returns one list of pairs where the first element is from the first list and the second element is from the second list. In our case we have that the result has type [(Int, a)]
with a
depending on the argument.
The replicate :: Int -> a -> [a]
function takes an integer that represents a length and an element x
and produces a list [x, x, x, ..., x]
of the given length.
The uncurry
function takes a function with type a -> b -> c
, i.e. with two arguments, and transforms it into a function with type (a, b) -> c
, i.e. with one argument that is a tuple. So uncurry replicate
has type (Int, a) -> [a]
.
Now the types match and you could map
the function over the zip
ed lists obtaining a [[a]]
and then using concat
to concatenate the results. concatMap
is simply a shorthand for concat . map
.
Alternatively instead of using zip
and then map
ing you can use the zipWith
function:
rep xs = concat $ zipWith replicate [1..] xs
Note that your solution seems to work correctly:
Prelude> let rep [] = []; rep (x:xs) = [ (x:xs)!! y | y <- [0..length xs], _<-[1..y+1]]
Prelude> rep [1,2,3]
[1,2,2,3,3,3]
Prelude> rep "abcd"
"abbcccdddd"
If you have an example where it doesn't produce the correct result please post it in your question.
However it is inefficient. You should avoid using !!
and length
when working with lists and prefer things like map
and fold
s.
Moreover I don't believe that the above function can produce the correct result for [Int]
but not for String
for one simple reason: the function is polymorphic and thus by parametricity it doesn't matter the type of elements that the list contains, it only matter its length, the result will always have the same shape (if you see the function is never "looking at"/"operating on" the elements, it simply moves them; it does exactly the same thing independently of their specific type.)
Upvotes: 5