# Dividir la lista en dos

I would like to implement a function that takes as input a size n and a list. This function will cut the list into two lists, one of size n and the rest in another list. I am new to this language and have a hard time learning the syntax.

The main problem I have is that is finding a way to express a size of the list without using any loops or mutable variables.

Can anyone give a me some pointers?

preguntado el 01 de febrero de 12 a las 22:02

What have you tried? At least you should give us a non-working version to show your efforts? -

Hint: you do not need to express the length of the list - all you need is a way to decrement `n`, and to check if it has reached zero. -

This may be slightly off topic, but there was a rather neat solution (by Juliet) that split a list in two halves, without knowing/specifying the length in advance: stackoverflow.com/questions/4866640/… -

## 4 Respuestas

Let's start with the function's type signature. Since it gets `n` and a list as arguments and returns a pair of lists, you have a function `split`:

``````val split : int -> 'a list -> 'a list * 'a list
``````

Here is one approach to implement this function:

``````let split n xs =
let rec splitUtil n xs acc =
match xs with
| [] -> List.rev acc, []
| _ when n = 0 -> List.rev acc, xs
| x::xs' -> splitUtil (n-1) xs' (x::acc)
splitUtil n xs []
``````

The idea is using an accumulator `acc` to hold elements you have traversed and decreasing `n` a long the way. Because elements are prepended to `acc`, in the end you have to reverse it to get the correct order.

The function has two base cases to terminate:

• There's no element left to traverse (`xs = []` en ese punto).
• You have gone through the first `n` elements of the list (`n` disminuye a `0` at that time).

Here is a short illustration of how `split` computes the result:

``````   split 2 [1; 2; 3] // call the auxiliary function splitUtil
~> splitUtil 2 [1; 2; 3] [] // match the 3rd case of x::xs'
~> splitUtil 1 [2; 3] [1] // match the 3rd case of x::xs'
~> splitUtil 0 [3] [2; 1] // match the 2nd case of n = 0 (base case)
~> List.rev [2; 1], [3] // call List.rev on acc
~> [1; 2], [3]
``````

Respondido 03 Feb 12, 03:02

Gracias por la explicación detallada. - user1072706

what role does the last "splitUtil n xs []" play in the function? - user1072706

@user1072706: it is an auxiliar function to avoid declaring `split` with an extra argument which is always an empty list. You can use `splitUtil` directly, then everything starts from the 2nd line. - almohadilla

@user1072706, it calls the inner function (`splitUtil`) with the initial parameters of the outer function (`split`), plus an empty `acc` to fill. - Benjol

``````let split n list =
let rec not_a_loop xs = function
| (0, ys) | (_, ([] as ys)) -> (List.rev xs), ys
| (n, x::ys) -> not_a_loop (x::xs) (n-1, ys)
not_a_loop [] (n, list)
``````

Respondido 02 Feb 12, 03:02

I dont understand too much your code but it seems that it uses a loop. I was thinking of doing some recurisve calls where i would specify n as the index and having as a base case return when the item in position n is found .. What do you think? - user1072706

That's more or less what this does, accumulating elements prior to `n` along the way. - Daniel

@user1072706 : No, it uses a recursive function llamado loop. The name is arbitrary, don't let it confuse you. - ildjarn

Thanks, what does the statement | (_,([] as ys)) translate to? - user1072706

There's a certain amount of irony here, considering the inner function is tail-recursive and therefore most likely compile to a loop. - Daniel

New solution - splitAt is now built into List and Array. See commit around 2014 on github. I noticed this today while using F# in VS.2015

Now you can simply do this...

``````let splitList n list =
List.splitAt n list
``````

And as you might expect the signature is...

``````n: int -> list: 'a list -> 'a list * 'a list
``````

Ejemplo de uso:

``````let (firstThree, remainder)  = [1;2;3;4;5] |> (splitList 3)
printfn "firstThree %A" firstThree
printfn "remainder %A" remainder
``````

Salida:

``````firstThree [1; 2; 3]
remainder [4; 5]
``````

Github for those interested: https://github.com/dsyme/visualfsharp/commit/1fc647986f79d20f58978b3980e2da5a1e9b8a7d

Respondido el 01 de Septiembre de 15 a las 05:09

One more way, using `fold`:

``````let biApply f (a, b) = (f a, f b)

let splitAt n list =
let splitter ((xs, ys), n') c =
if n' < n then
((c :: xs, ys), n' + 1)
else
((xs, c :: ys), n' + 1)
List.fold splitter (([], []), 0) list
|> fst
|> biApply List.rev
``````

Aquí is a great series on folds than you can follow to learn more on the topic.

Respondido 04 Feb 12, 22:02

Doesn't this function walk through the todo list, instead of just up to n? - Henrik

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.