billbob
billbob

Reputation: 41

Haskell: create a tuple of lists from an input list

I am trying to set up some functions to help with a current project I am working on. I am new to Haskell and struggling to implement my desired functions.

I have a list [a] and would like it to output a tuple of four different lists ([b],[b],[b],[b]) where each item in list [a] is successively placed in to the next list in the output tuple. So the first element in the input list [a] goes to the first list [b], the second element in [a] goes to the second list [b], the third element in [a] goes to the third list [b], and so on. I have tried using chunksOf and splitEvery/splitAt but cannot get the correct output. And help would be greatly appreciated! Thanks!

Upvotes: 3

Views: 588

Answers (2)

Elmex80s
Elmex80s

Reputation: 3504

Define

f n = transpose . chunksOf n
g xs = let [xs1, xs2, xs3, xs4] = f 4 xs in (xs1, xs2, xs3, xs4) 

Where f is the general solution. This gives

Prelude> g ['a' .. 'z']
("aeimquy","bfjnrvz","cgkosw","dhlptx") 

Signatures

Prelude> :t g
g :: [a] -> ([a], [a], [a], [a])

and

Prelude> :t f
f :: Int -> [a] -> [[a]]

Info on:

Upvotes: 3

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476584

You each time "rotate" the 4-tuple and prepend to the first element. So we can implement this with a foldr pattern that looks like:

toFour :: [a] -> ([a], [a], [a], [a])
toFour = foldr (\a (bs, cs, ds, as) -> (a:as, bs, cs, ds)) ([], [], [], [])

or with an irrefutable pattern:

toFour :: [a] -> ([a], [a], [a], [a])
toFour = foldr (\a ~(bs, cs, ds, as) -> (a:as, bs, cs, ds)) ([], [], [], [])

So here (bs, cs, ds, as) is the 4-tuple that we generated for the tail of the list, and we "rotate" to the right to construct the tuple (as, bs, cs, ds) and then prepend the item a to the first list of the 4-tuple.

For a list of integers, this gives us:

Prelude> toFour [1..2]
([1],[2],[],[])
Prelude> toFour [1..3]
([1],[2],[3],[])
Prelude> toFour [1..4]
([1],[2],[3],[4])
Prelude> toFour [1..5]
([1,5],[2],[3],[4])
Prelude> toFour [1..6]
([1,5],[2,6],[3],[4])
Prelude> toFour [1..10]
([1,5,9],[2,6,10],[3,7],[4,8])

When we work with the irrefutable pattern, this is done lazily, so we can for example distribute elements of an infinite list, and then take for example obtain the first 10 elements of the second item:

Prelude> (\(_, l, _, _) -> take 10 l) (toFour [1..])
[2,6,10,14,18,22,26,30,34,38]

Upvotes: 7

Related Questions