Distribute List in list tuple (Haskell)

3

We have the following function:

repartir [a] -> ([a],[a])

In order to distribute, you must distribute the main list in two lists, taking the elements in this way:

repartir [1,2,3,4,5]

---> ([1,3,5],[2,4])

repartir "hola"

---> ("hl","oa")

We can only import: import Data.List

Greetings and thanks

    
asked by Ramosaurio 25.10.2016 в 09:45
source

3 answers

1

A straightforward way:

repartir :: [a] -> ([a],[a])
repartir xs = ([xs!!i | i <- [0,2..n]], [xs!!i | i <- [1,3..n]])
    where n = length xs - 1

The operator !! is not very efficient in lists, so you do not have to abuse it. A more effective version:

repartir :: [a] -> ([a],[a])
repartir xs = ([x | (i,x) <- zs, odd i], [x | (i,x) <- zs, even i])
    where zs = zip [1..] xs

PS: it was not necessary to import the Data.List module since the necessary functions are included in Prelude

There is a better solution using Either types. The bad thing is that you need to import the Data.Either module:

import Data.Either (partitionsEithers)

repartir :: [a] -> ([a],[a])
repartir = partitionEithers . zipWith id (cycle [Left,Right])
    
answered by 26.10.2016 / 02:22
source
2

A more efficient solution, without using functions of the Data.List module and going through the list one time, may be this:

repartir :: [a] -> ([a],[a])
repartir = repartir' True

repartir' :: Bool -> [a] -> ([a],[a])
repartir' _ [] = ([],[])
repartir' g (x:xs) = let (a,b) = repartir' (not g) xs in if g then (x:a,b) else (a,x:b)
    
answered by 26.10.2016 в 14:56
1

In these cases it is best to go step by step to simplify the problem.

The cast can be seen as two separate cases (the two elements of the tuple). The first takes two of the list discarding the second and the second of the tuple is also two but discarding the first.

For the first:

reparte1 :: [a] -> [a]                       -- firma
reparte1 (x:_:xs) = x : reparte1 xs          -- tomo el 1ro, descarto el 2do

But ...

*Main> reparte1 "hola"
"hl*** Exception: Non-exhaustive patterns in function reparte1

The obvious is missing, the closing case. Now it would be:

reparte1 :: [a] -> [a]                       -- firma
reparte1 [] = []                             -- fin
reparte1 (x:_:xs) = x : reparte1 xs          -- tomo el 1ro, descarto el 2do

Now it fails on odd:

*Main> reparte1 "hola"
"hl"
*Main> reparte1 "holas"
"hl*** Exception: Non-exhaustive patterns in function reparte1

Easy to solve. You add this case:

reparte1 :: [a] -> [a]                       -- firma
reparte1 [] = []                             -- fin
reparte1 [x] = [x]                           -- cuando quede uno me lo quedo
reparte1 (x:_:xs) = x : reparte1 xs          -- tomo el 1ro, descarto el 2do

*Main> reparte1 "hola"
"hl"
*Main> reparte1 "holas"
"hls"

Case 2 is the same but you discard the first element and you keep the second one. You ignore it.

reparte2 :: [a] -> [a]                       -- firma
reparte2 [] = []                             -- fin
reparte2 [x] = []                            -- cuando quede uno lo ignoro
reparte2 (_:x:xs) = x : reparte2 xs          -- descarto el 1ro, tomo el 2do

*Main> reparte2 "holas"
"oa"

And finally together the two cases.

repartir :: [a] -> ([a],[a])
repartir (x) = (reparte1 x, reparte2 x)

*Main> repartir [1,2,3,4,5]
([1,3,5],[2,4])
*Main> repartir "hola"
("hl","oa")

Optimization is left to the student. ;-)

    
answered by 25.10.2016 в 22:04