2

I have this list of tuples

[(4,'a'), (1,'b'), (2,'c'), (2,'a'), (1,'d'), (4,'e')]

I want to get the first elements of every tuple then replicate it to make the following: "aaaabccaadeeee"

I came up with this code, but it only gives me the replicate of the first tuple.

replicate  (fst ( head [(4,'a'), (1,'b')])) ( snd ( head [(4,'a'), (1,'b')]))
--output is: "aaaa"

I was thinking to use map for to get the replicate of every tuple, but I didn't succeed.

Tyler Joe
  • 357
  • 2
  • 18
  • 1
    It's usually much clearer not to work with `fst` and `snd` (and definitely not with `head` or `!!`) but instead use _pattern matching_ to get at the elements. And for doing stuff with elements of lists (be they tuples or something else), list comprehensions are syntactically very nice. – leftaroundabout Nov 16 '18 at 00:38
  • 2
    `f = (>>= uncurry replicate)` is the fancy-pants approach. – amalloy Nov 16 '18 at 01:05
  • 1
    Your list is `ils` in `[s | (n,c) <- ils, s <- replicate n c]` produces the output you require. – fp_mora Nov 16 '18 at 02:20
  • map returns the array of the same size. So in this example it will give you array on strings. To do it in one operation you need fold function, which gives the accumulated result. – Manoj R Nov 16 '18 at 05:44

3 Answers3

6

Since you already know how to find the correct answer for a single element, all you need is a little recursion

func :: [(Int, a)] -> [a]
func [] = []
func ((n, elem):rest) = (replicate n elem) ++ (func rest)

Mapping the values should also work. You just need to concatenate the resulting strings into one.

func :: [(Int, a)] -> [a]
func xs = concat $ map func2 xs where 
              func2 (n, elem) = replicate n elem

Or, if you are familiar with currying:

func :: [(Int, a)] -> [a]
func xs = concat $ map (uncurry replicate) xs

Finally, if you are comfortable using function composition, the definition becomes:

func :: [(Int, a)] -> [a]
func = concat . map (uncurry replicate)

Using concat and map is so common, there is a function to do just that. It's concatMap.

func :: [(Int, a)] -> [a]
func = concatMap (uncurry replicate)
merlyn
  • 2,273
  • 1
  • 19
  • 26
2

Let

ls = [(4,'a'), (1,'b'), (2,'c'), (2,'a'), (1,'d'), (4,'e')] 

in

concat [replicate i x | (i, x) <- ls]

will give

"aaaabccaadeeee"

The point-free version

concat . map (uncurry replicate) 
Elmex80s
  • 3,428
  • 1
  • 15
  • 23
1

You are correct about trying to use map. But first lets see why your code did not work

replicate  (fst ( head [(4,'a'), (1,'b')])) ( snd ( head [(4,'a'), (1,'b')]))

Your first parameter to replicate is the head of your list which is (4, 'a'). Then you are calling fst on this, thus the first parameter is 4. Same things happens with second parameter and you get 'a'. The result of which you see.

Before using map lets try to do this with recursion. You want to take one element of list and apply replicate to it and then combine it with the result of applying replicate on the second element.

generate [] = []    
generate (x:xs) = replicate (fst x) (snd x) ++ generate xs

Do note I am using pattern matching to get the first element of list. You can us the pattern matching to get the element inside the tuple as well, and then you would not need to use the fst/snd functions. Also note I am using pattern matching to define the base case of empty list.

generate [] = []
generate ((x,y):xs) = replicate x y ++ generate xs

Now coming to map, so map will apply your function to every element of the list, here's the first try

generate (x,y) = replicate x y
map generate  xs

The result of the above will be slightly different from recursion. Think about it, map is going to apply generate to every element and store the result in a list. generate creates a list. So when you apply map you are creating a list of list. You can use concat to flatten it if you want, which will give you the same result as recursion.

Last thing, if you can use recursion, then you can use fold as well. Fold will just apply a function to every element of the list and return the accumulated results (broadly speaking).

--first parameter is the function to apply, second is the accumulator, third is your list
foldr step [] xs
   where step (x,y) acc = 
                   (replicate x y) ++ acc

Again here I have used pattern matching in the function step to extract the elements of the tuple out.

peeyush singh
  • 1,337
  • 1
  • 12
  • 23