yeshika Senadeera
yeshika Senadeera

Reputation: 117

Repeating each successive element in the input list one more than the previous element

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

Answers (1)

Bakuriu
Bakuriu

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 ziped 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 maping 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 folds.

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

Related Questions