Splitting a list F Sharp - list

I'm trying to write a method that splits a list into two. The function should return a tuple of the two lists and the arguments that the function takes are the # of items on the first list, and then the list. Here's what I mean
list [1,2,3,4]
split(1,list)-> ([1],[2,3,4])
split (3,list) -> ([1,2,3],[4])
Here's what I have so far:
let rec mysplit = function
|(n,[])->([],[])
|(1,x::xs)->(x::[],xs)
|(n,x::xs)-> mysplit(n-1,xs)
I'm not exactly sure how to "catch" the tuple back from the recursive call. Not sure where to have an extra let statement in there to temporarily save the list I'm building up. New to the language so a couple of different approaches would be good to learn.

Skip and take are your friends here. I don't think you need to do any sort of matches or recursive calls when there's a direct approach.
let split n l = (l |> Seq.take n, l |> Seq.skip n)
As for possible edge cases, skip will return an empty sequence if there are > n elements in the list, and take will return the first n elements if there are < n elements in the sequence.
Tried it in TryFharp.org with your examples and it works as expected.

A straightforward implementation would be:
let rec mysplit = function
|(n,[])->([],[])
|(1,x::xs)->(x::[],xs)
|(n,x::xs)-> let (f, s) = mysplit(n-1,xs) in (x::f, s)
You could also write a tail-recursive version:
let mysplit (n, l) =
let rec mysplit' n' (f, s) = function
| [] -> (f, s)
| (x::xs) as l' -> if n' = 0 then (f, l') else mysplit' (n'-1) (x::f, xs) xs
let (f', s) = mysplit' n ([], []) l in (List.rev f', s)

Lee's answer shows you a working solution, but to answer your specific question, you can capture values returned to you in a tuple like so:
let before, after = mysplit (2, [1;2;3;4;5])
You can also use this trick to declare multiple variables in a single let statement:
let i, j, k = (1, 2, 3)

Related

Split a list in two and preserve order

How do you efficiently split a list in 2, preserving the order of the elements?
Here's an example of input and expected output
[] should produce ([],[])
[1;] can produce ([1;], []) or ([], [1;])
[1;2;3;4;] should produce ([1; 2;], [3; 4;])
[1;2;3;4;5;] can produce ([1;2;3;], [4;5;]) or ([1;2;], [3;4;5;])
I tried a few things but I'm unsure which is the most efficient... Maybe there is a solution out there that I'm missing completely(calls to C code don't count).
My first attempt was to use List's partition function with a ref to 1/2 the length of the list. This works but you walk through the whole list when you only need to cover half.
let split_list2 l =
let len = ref ((List.length l) / 2) in
List.partition (fun _ -> if !len = 0 then false else (len := !len - 1; true)) l
My next attempt was to use a accumulator and then reverse it. This only walks through half the list but I call reverse to correct the order of the accumulator.
let split_list4 l =
let len = List.length l in
let rec split_list4_aux ln acc lst =
if ln < 1
then
(List.rev acc, lst)
else
match lst with
| [] -> failwith "Invalid split"
| hd::tl ->
split_list4_aux (ln - 1) (hd::acc) tl in
split_list4_aux (len / 2) [] l
My final attempt used function closures for the accumulator and it works but I have no idea how efficient closures are.
let split_list3 l =
let len = List.length l in
let rec split_list3_aux ln func lst =
if ln < 1
then
(func [], lst)
else
match lst with
| hd::tl -> split_list3_aux (ln - 1) (fun t -> func (hd::t)) tl
| _ -> failwith "Invalid split" in
split_list3_aux (len / 2) (fun t -> t) l
So is there a standard way to split a list in OCaml(preserving element order) that's most efficient?
You need to traverse the whole list for all of your solutions. The List.length function traverses the whole list. But it's true that your later solutions re-use the tail of the original list rather than constructing a new list.
It is difficult to say how fast any given bit of code is going to be just by inspection. Generally it's good enough to think in aysmptotic O(f(n)) terms, then work on slow functions in detail through timing tests (of realistic data).
All of your answers look to be O(n), which is the best you can do since you clearly need to know the length of the list to get the answer.
Your split_list2 and split_list3 solutions look pretty complicated to me, so I would expect (intuitively) them to be slower. A closure is a fairly complicated data structure containing a function and the environment of accessible variables. So it's problaby not all that fast to construct one.
Your split_list4 solution is what I would code up myself.
If you really care about timings you should time your solutions on some long lists. Keep in mind that you might get different timings on different systems.
Couldn't give up this question. I had to find a way that I could walk through this list one time to create a split with order preserved..
How about this?
let split lst =
let cnt = ref 0 in
let acc = ref ([], []) in
let rec split_aux c l =
match l with
| [] -> cnt := (c / 2)
| hd::tl ->
(
split_aux (c + 1) tl;
let (f, s) = (!acc) in
if c < (!cnt)
then
acc := ((hd::f), s)
else
acc := (f, hd::s)
)
in
split_aux 0 lst; !acc

F# Fold while building a list using cons (::) as opposed to concat (#)

I have the following function which does what I want. But is uses the concat (#) operator which is O(n) as opposed to O(1) for the (::) operator
let myFunc s m cs =
let n = s * m
let c = [n - s] // single element list
(n, cs # c) // concat the new value to the accumulated list
let chgLstAndLast =
[0.99; 0.98; 1.02]
|> List.fold (fun (s, cs) m -> myFunc s m cs) (1., [])
The chgLstAndLast returns the last value and list of the results generated:
val chgLstAndLast : float * float list = (0.989604, [-0.01; -0.0198; 0.019404])
I would like to improve the above in three ways.
Use con (::) rather than concat (#)
Move the list accumulation from the myFunc to the List.fold operation
Make sure that the resulting list order remains the same as above (i.e last result is at end of list as opposed to the head)
For example, I would like to write a myFunc like this
let myFunc s m cs =
let n = s * m
let c = n - s // single element, but not as list
(n, c) // No concat here
But when I do, I don't see how to use (::) cons in the Fold function.
If I understand your code correctly, what you want to do is a fold while keeping all intermediary results. This is almost what List.scan does; it also returns the initial state.
let chgLstAndLast data =
let inner s m =
let n = s * m
n, n - s
let processedData = data |> List.scan (fun (s, _) n -> inner s n) (1.0, 1.0)
let lastResult = processedData |> List.reduce (fun _ n -> n)
let seq = processedData |> List.tail |> List.map snd
lastResult, seq
To explain a bit more on this code: first I declare an inner function to make the code cleaner to the exterior world (assuming myFunc isn't needed by other code), then I use scan to get all intermediary results from a fold, which is a built-in way to do your fold + accumulator trick.
The last value is obtained with a reduce trick since there's no built-in "last of list" function, and the intermediary results are the second parts of the processed data, except for the first element which is the initial state.

OCaml code that works on 2 lists. Is there a better way of doing this

I have to iterate over 2 lists. One starts off as a list of empty sublists and the second one has the max length for each of the sublists that are in the first one.
Example; list1 = [[];[];[];]; list2 = [1;2;3]
I need to fill out the empty sublists in list1 ensuring that the length of the sublists never exceed the corresponding integer in list2. To that end, I wrote the following function, that given an element, elem and 2 two lists list and list, will fill out the sublists.
let mapfn elem list1 list2=
let d = ref 1 in
List.map2 (fun a b -> if ((List.length a) < b) && (!d=1)
then (incr d ; List.append a [elem])
else a )
list1 list2
;;
I can now call this function repeatedly on the elements of a list and get the final answer I need
This function works as expected. But I am little bothered by the need to use the int ref d.
Is there a better way for me to do this.
I always find it worthwhile to split the problem into byte-sized pieces that can be composed together to form a solution. You want to pad or truncate lists to a given length; this is easy to do in two steps, first pad, then truncate:
let all x = let rec xs = x :: xs in xs
let rec take n = function
| [] -> []
| _ when n = 0 -> []
| x :: xs -> x :: take (pred n) xs
all creates an infinite list by repeating a value, while take extracts the prefix sublist of at most the given length. With these two, padding and truncating is very straightforwad:
let pad_trim e n l = take n (l # all e)
(it might be a bit surprising that this actually works in a strict language like OCaml). With that defined, your required function is simply:
let mapfn elem list1 list2 = List.map2 (pad_trim elem) list2 list1
that is, taking the second list as a list of specified lengths, pad each of the lists in the first list to that length with the supplied padding element. For instance, mapfn 42 [[];[];[]] [1;2;3] gives [[42]; [42; 42]; [42; 42; 42]]. If this is not what you need, you can tweak the parts and their assembly to suit your requirements.
Are you looking for something like that?
let fill_list elem lengths =
let rec fill acc = function
| 0 -> acc
| n -> fill (elem :: acc) (n - 1) in
let accumulators = List.map (fun _ -> []) lengths in
List.map2 fill accumulators lengths
(* toplevel test *)
# let test = fill_list 42 [1; 3];;
val test : int list list = [[42]; [42; 42; 42]]
(I couldn't make sense of the first list of empty lists in your question, but I suspect it may be the accumulators for the tail-rec fill function.)

How to partition a list with a given group size?

I'm looking for the best way to partition a list (or seq) so that groups have a given size.
for ex. let's say I want to group with size 2 (this could be any other number though):
let xs = [(a,b,c); (a,b,d); (y,z,y); (w,y,z); (n,y,z)]
let grouped = partitionBySize 2 input
// => [[(a,b,c);(a,b,d)]; [(y,z,y);(w,y,z)]; [(n,y,z)]]
The obvious way to implement partitionBySize would be by adding the position to every tuple in the input list so that it becomes
[(0,a,b,c), (1,a,b,d), (2,y,z,y), (3,w,y,z), (4,n,y,z)]
and then use GroupBy with
xs |> Seq.ofList |> Seq.GroupBy (function | (i,_,_,_) -> i - (i % n))
However this solution doesn't look very elegant to me.
Is there a better way to implement this function (maybe with a built-in function)?
This seems to be a repeating pattern that's not captured by any function in the F# core library. When solving similar problems earlier, I defined a function Seq.groupWhen (see F# snippets) that turns a sequence into groups. A new group is started when the predicate holds.
You could solve the problem using Seq.groupWhen similarly to Seq.group (by starting a new group at even index). Unlike with Seq.group, this is efficient, because Seq.groupWhen iterates over the input sequence just once:
[3;3;2;4;1;2;8]
|> Seq.mapi (fun i v -> i, v) // Add indices to the values (as first tuple element)
|> Seq.groupWhen (fun (i, v) -> i%2 = 0) // Start new group after every 2nd element
|> Seq.map (Seq.map snd) // Remove indices from the values
Implementing the function directly using recursion is probably easier - the solution from John does exactly what you need - but if you wanted to see a more general approach then Seq.groupWhen may be interesting.
List.chunkBySize (hat tip: Scott Wlaschin) is now available and does exactly what you're talking about. It appears to be new with F# 4.0.
let grouped = [1..10] |> List.chunkBySize 3
// val grouped : int list list =
// [[1; 2; 3]; [4; 5; 6]; [7; 8; 9]; [10]]
Seq.chunkBySize and Array.chunkBySize are also now available.
Here's a tail-recursive function that traverses the list once.
let chunksOf n items =
let rec loop i acc items =
seq {
match i, items, acc with
//exit if chunk size is zero or input list is empty
| _, [], [] | 0, _, [] -> ()
//counter=0 so yield group and continue looping
| 0, _, _::_ -> yield List.rev acc; yield! loop n [] items
//decrement counter, add head to group, and loop through tail
| _, h::t, _ -> yield! loop (i-1) (h::acc) t
//reached the end of input list, yield accumulated elements
//handles items.Length % n <> 0
| _, [], _ -> yield List.rev acc
}
loop n [] items
Usage
[1; 2; 3; 4; 5]
|> chunksOf 2
|> Seq.toList //[[1; 2]; [3; 4]; [5]]
I like the elegance of Tomas' approach, but I benchmarked both our functions using an input list of 10 million elements. This one clocked in at 9 secs vs 22 for his. Of course, as he admitted, the most efficient method would probably involve arrays/loops.
What about a recursive approach? - only requires a single pass
let rec partitionBySize length inp dummy =
match inp with
|h::t ->
if dummy |> List.length < length then
partitionBySize length t (h::dummy)
else dummy::(partitionBySize length t (h::[]))
|[] -> dummy::[]
Then invoke it with partitionBySize 2 xs []
let partitionBySize size xs =
let sq = ref (seq xs)
seq {
while (Seq.length !sq >= size) do
yield Seq.take size !sq
sq := Seq.skip size !sq
if not (Seq.isEmpty !sq) then yield !sq
}
// result to list, if you want
|> Seq.map (Seq.toList)
|> Seq.toList
UPDATE
let partitionBySize size (sq:seq<_>) =
seq {
let e = sq.GetEnumerator()
let empty = ref true;
while !empty do
yield seq { for i = 1 to size do
empty := e.MoveNext()
if !empty then yield e.Current
}
}
array slice version:
let partitionBySize size xs =
let xa = Array.ofList xs
let len = xa.Length
[
for i in 0..size..(len-1) do
yield ( if i + size >= len then xa.[i..] else xa.[i..(i+size-1)] ) |> Array.toList
]
Well, I was late for the party. The code below is a tail-recursive version using high-order functions on List:
let partitionBySize size xs =
let i = size - (List.length xs - 1) % size
let xss, _, _ =
List.foldBack( fun x (acc, ls, j) ->
if j = size then ((x::ls)::acc, [], 1)
else (acc, x::ls, j+1)
) xs ([], [], i)
xss
I did the same benchmark as Daniel did. This function is efficient while it is 2x faster than his approach on my machine. I also compared it with an array/loop version, they are comparable in terms of performance.
Moreover, unlike John's answer, this version preserves order of elements in inner lists.

Split list into two equal lists in F#

I'm really new to F#, and I need a bit of help with an F# problem.
I need to implement a cut function that splits a list in half so that the output would be...
cut [1;2;3;4;5;6];;
val it : int list * int list = ([1; 2; 3], [4; 5; 6])
I can assume that the length of the list is even.
I'm also expected to define an auxiliary function gencut(n, xs) that cuts xs into two pieces, where n gives the size of the first piece:
gencut(2, [1;3;4;2;7;0;9]);;
val it : int list * int list = ([1; 3], [4; 2; 7; 0; 9])
I wouldn't normally ask for exercise help here, but I'm really at a loss as to where to even start. Any help, even if it's just a nudge in the right direction, would help.
Thanks!
Since your list has an even length, and you're cutting it cleanly in half, I recommend the following (psuedocode first):
Start with two pointers: slow and fast.
slow steps through the list one element at a time, fast steps two elements at a time.
slow adds each element to an accumulator variable, while fast moves foward.
When the fast pointer reaches the end of the list, the slow pointer will have only stepped half the number of elements, so its in the middle of the array.
Return the elements slow stepped over + the elements remaining. This should be two lists cut neatly in half.
The process above requires one traversal over the list and runs in O(n) time.
Since this is homework, I won't give a complete answer, but just to get you partway started, here's what it takes to cut the list cleanly in half:
let cut l =
let rec cut = function
| xs, ([] | [_]) -> xs
| [], _ -> []
| x::xs, y::y'::ys -> cut (xs, ys)
cut (l, l)
Note x::xs steps 1 element, y::y'::ys steps two.
This function returns the second half of the list. It is very easy to modify it so it returns the first half of the list as well.
You are looking for list slicing in F#. There was a great answer by #Juliet in this SO Thread: Slice like functionality from a List in F#
Basically it comes down to - this is not built in since there is no constant time index access in F# lists, but you can work around this as detailed. Her approach applied to your problem would yield a (not so efficient but working) solution:
let gencut(n, list) =
let firstList = list |> Seq.take n |> Seq.toList
let secondList = list |> Seq.skip n |> Seq.toList
(firstList, secondList)
(I didn't like my previous answer so I deleted it)
The first place to start when attacking list problems is to look at the List module which is filled with higher order functions which generalize many common problems and can give you succinct solutions. If you can't find anything suitable there, then you can look at the Seq module for solutions like #BrokenGlass demonstrated (but you can run into performance issues there). Next you'll want to consider recursion and pattern matching. There are two kinds of recursion you'll have to consider when processing lists: tail and non-tail. There are trade-offs. Tail-recursive solutions involve using an accumulator to pass state around, allowing you to place the recursive call in the tail position and avoid stack-overflows with large lists. But then you'll typically end up with a reversed list! For example,
Tail-recursive gencut solution:
let gencutTailRecursive n input =
let rec gencut cur acc = function
| hd::tl when cur < n ->
gencut (cur+1) (hd::acc) tl
| rest -> (List.rev acc), rest //need to reverse accumulator!
gencut 0 [] input
Non-tail-recursive gencut solution:
let gencutNonTailRecursive n input =
let rec gencut cur = function
| hd::tl when cur < n ->
let x, y = gencut (cur+1) tl //stackoverflow with big lists!
hd::x, y
| rest -> [], rest
gencut 0 input
Once you have your gencut solution, it's really easy to define cut:
let cut input = gencut ((List.length input)/2) input
Here's yet another way to do it using inbuilt library functions, which may or may not be easier to understand than some of the other answers. This solution also only requires one traversal across the input. My first thought after I looked at your problem was that you want something along the lines of List.partition, which splits a list into two lists based on a given predicate. However, in your case this predicate would be based on the index of the current element, which partition cannot handle, short of looking up the index for each element.
We can accomplish creating our own equivalent of this behavior using a fold or foldBack. I will use foldBack here as it means you won't have to reverse the lists afterward (see Stephens excellent answer). What we are going to do here is use the fold to provide our own index, along with the two output lists, all as the accumulator. Here is the generic function that will split your list into two lists based on n index:
let gencut n input =
//calculate the length of the list first so we can work out the index
let inputLength = input |> List.length
let results =
List.foldBack( fun elem acc->
let a,b,index = acc //decompose accumulator
if (inputLength - index) <= n then (elem::a,b,index+1)
else (a,elem::b,index+1) ) input ([],[],0)
let a,b,c = results
(a,b) //dump the index, leaving the two lists as output.
So here you see we start the foldBack with an initial accumulator value of ([],[],0). However, because we are starting at the end of the list, the 0 representing the current index needs to be subtracted from the total length of the list to get the actual index of the current element.
Then we simply check if the current index falls within the range of n. If it does, we update the accumulator by adding the current element to list a, leave list b alone, and increase the index by 1 : (elem::a,b,index+1). In all other cases, we do exactly the same but add the element to list b instead: (a,elem::b,index+1).
Now you can easily create your function that splits a list in half by creating another function over this one like so:
let cut input =
let half = (input |> List.length) / 2
input |> gencut half
I hope that can help you somewhat!
> cut data;;
val it : int list * int list = ([1; 2; 3], [4; 5; 6])
> gencut 5 data;;
val it : int list * int list = ([1; 2; 3; 4; 5], [6])
EDIT: you could avoid the index negation by supplying the length as the initial accumulator value and negating it on each cycle instead of increasing it - probably simpler that way :)
let gencut n input =
let results =
List.foldBack( fun elem acc->
let a,b,index = acc //decompose accumulator
if index <= n then (elem::a,b,index-1)
else (a,elem::b,index-1) ) input ([],[],List.length input)
let a,b,c = results
(a,b) //dump the index, leaving the two lists as output.
I have the same Homework, this was my solution. I'm just a student and new in F#
let rec gencut(n, listb) =
let rec cut n (lista : int list) (listb : int list) =
match (n , listb ) with
| 0, _ -> lista, listb
| _, [] -> lista, listb
| _, b :: listb -> cut (n - 1) (List.rev (b :: lista )) listb
cut n [] listb
let cut xs = gencut((List.length xs) / 2, xs)
Probably is not the best recursive solution, but it works. I think
You can use List.nth for random access and list comprehensions to generate a helper function:
let Sublist x y data = [ for z in x..(y - 1) -> List.nth data z ]
This will return items [x..y] from data. Using this you can easily generate gencut and cut functions (remember to check bounds on x and y) :)
check this one out:
let gencut s xs =
([for i in 0 .. s - 1 -> List.nth xs i], [for i in s .. (List.length xs) - 1 -> List.nth xs i])
the you just call
let cut xs =
gencut ((List.length xs) / 2) xs
with n durationn only one iteration split in two