ricky_study
ricky_study

Reputation: 7

Haskell duplicate the value in a list according to its position

I am pretty new to Haskell. I am trying to write a program that takes a list and returns a list of one copy of the first element of the input list, followed by two copies of the second element, three copies of the third, and so on. e.g. input [1,2,3,4], return [1,2,2,3,3,3,4,4,4,4].

import Data.List

triangle :: [a] -> [a]
triangle (x:xs)
    |x/=null   = result ++ xs
    |otherwise = group(sort result)
    where result = [x]

I try to use ++ to add each list into a new list then sort it, but it does not work. What I tried to achieve is, for example: the list is [1,2,3], result = [1,2,3]++[2,3]++[3] but sorted.

Upvotes: 0

Views: 944

Answers (3)

Will Ness
Will Ness

Reputation: 71109

update: now I see what you mean here. you want to take diagonals on tails. nice idea. :) Here's how:

import Data.Universe.Helpers
import Data.List             (tails)

bar :: [a] -> [a]
bar = concat . diagonals . tails

That's it!

Trying it out:

> concat . diagonals . tails $ [1..3]
[1,2,2,3,3,3]

Or simply,

>  diagonal . tails $ [11..15]
[11,12,12,13,13,13,14,14,14,14,15,15,15,15,15]

(previous version of the answer:)

Have you heard about list comprehensions, number enumerations [1..] and the zip function?

It is all you need to implement your function:

foo :: [a] -> [a]
foo xs = [ x | (i,x) <- zip [1..] xs, j <- .... ]

Can you see what should go there instead of the ....? It should produce some value several times (how many do we need it to be?... how many values are there in e.g. [1..10]?) and then we will ignore the produced value, putting x each time into the resulting list, instead.

Upvotes: 0

Random Dev
Random Dev

Reputation: 52290

here is a short version

triangle :: [a] -> [a]
triangle = concat . zipWith replicate [1..]

How it works

zipWith takes a function f : x -> y -> z and two lists [x1,x2,...] [y1,y2,..] and produces a new list [f x1 y1, f x2 y2, ...]. Both lists may be infinite - zipWith will stop as soon one of the list run out of elements (or never if both are infinite).

replicate : Int -> a -> [a] works like this: replicate n x will produce a list with n-elements all x - so replicate 4 'a' == "aaaa".

[1..] = [1,2,3,4,...] is a infinite list counting up from 1

so if you use replicate in zipWith replicate [1..] [x1,x2,...] you get

[replicate 1 x1, replicate 2 x2, ..]
= [[x1], [x2,x2], ..]

so a list of lists - finally concat will append all lists in the list-of-lists together to the result we wanted

the final point: instead of triangle xs = concat (zipWith replicate [1..] xs) you can write triangle xs = (concat . zipWith repliate [1..]) xs by definition of (.) and then you can eta-reduce this to the point-free style I've given.

Upvotes: 2

Ari Fordsham
Ari Fordsham

Reputation: 2515

Here you go:

triangle :: [Int] -> [Int]
triangle = concat . go 1
    where
        go n [] = []
        go n (x:xs) = (replicate n x) : (go (n+1) xs)

Upvotes: 0

Related Questions