# 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

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])
``````

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)
``````

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. ;-)