How to partition a list with a given group size? - list

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.

Related

How to reshape a list

So consider getting a list of [1; 2; 3; 4; 5; 6; 7; 8; 9] and reshape it into [[1; 2; 3]; [4; 5; 6]; [7; 8; 9]]. How would you do that in OCaml? I want a simple function or something from the standard library.
Turns out, it can be easily done with 3 lines of code, considering that the length of the list is divisible by 3.
let rec re_shape = function
| x :: xs :: xz :: xt -> [x; xs; xz] :: re_shape xt
| _ -> []
How this works is that for each iteration it cons a list of 3 to the rest of the function, till it reaches the end. The last line is added for safety.
As you have shown an effort to solve this, for your consideration, see a strategy below for generalizing this to allow for any length.
The partition function will allow us to get the first n elements from the list and the remainder, raising Invalid_argument if there aren't n elements in the list.
The chunks function applies this recursively to the remainder to build a list of lists.
let partition n lst =
let rec partition' n (first, rest) =
match n, rest with
| 0, _ -> (List.rev first, rest)
| _, [] -> raise (Invalid_argument "List not long enough")
| _, x::xs -> partition' (n-1) (x :: first, xs)
in
partition' n ([], lst)
let rec chunks n lst =
match partition n lst with
| first, [] -> [first]
| first, rest -> first :: chunks n rest
| exception (Invalid_argument _) ->
raise (Invalid_argument (Format.sprintf "List length not evenly divisible by %d" n))
This second function is not tail-recursive, though that can readily be addressed in OCaml 4.14 and later with:
let[#tail_mod_cons] rec chunks n lst =
...

F# Splitting a list

I am new to F# & tuples and I am trying to split a list into three lists of tuples using recursion and matching.
For example, a list of [1; 2; 3] would return:
l1 = [1]
l2 = [2]
l3 = [3]
or
[1;2;3;4;5;6;7]:
l1 = [1;2;3]
l2 = [4; 5]
l3 = [6; 7]
So far my code starts out as
let rec split x =
match x with
| _ -> [], [], []
I'm not sure where to start when inserting elements into each list.
The most basic approach would be to walk over the list, process the rest of it recursively and then append the current element to one of the three returned lists. You will need to add an extra parameters i to the function to keep track of how far in the list you are (and then use this to determine where should the current elemnt go). The general structure in the most basic form is:
let split l =
let length = List.length l
let rec loop i l =
match l with
| [] ->
// Empty list just becomes a triple of empty lists
[], [], []
| x::xs ->
// Process the rest of the list recursively. This
// gives us three lists containing the values from 'xs'
let l1, l2, l3 = loop (i + 1) xs
// Now comes the tricky bit. Here you need to figure out
// whether 'x' should go into 'l1', 'l2' or 'l3'.
// Then you can append it to one of them using something like:
l1, x::l2, l3
// Walk over the list, starting with index 'i=0'
loop 0 l
What to do about the tricky bit? I do not have a solution that works exactly as you wanted, but the following is close - it simply looks whether i is greater than 1/3 of the length or 2/3 of the length:
let split l =
let length = List.length l
let rec loop i l =
match l with
| [] -> [], [], []
| x::xs ->
let l1, l2, l3 = loop (i + 1) xs
if i >= length / 3 * 2 then l1, l2, x::l3
elif i >= length / 3 then l1, x::l2, l3
else x::l1, l2, l3
loop 0 l
This will always create groups of length / 3 and put remaining elements in the last list:
split [1..3] // [1], [2], [3]
split [1..4] // [1], [2], [3; 4]
split [1..5] // [1], [2], [3; 4; 5]
split [1..6] // [1; 2], [3; 4], [5; 6]
You should be able to adapt this to the behaviour you need - there is some fiddly calculation that you need to do to figure out exactly where the cut-off points are, but that's a matter of getting the +/-1s right!
There is a function for that in the List module.
You can test it easily in F# interactive (fsi).
let input = [1;2;3];;
let output = List.splitInto 3 input;;
output;;
val it : int list list = [[1]; [2]; [3]]
So it returns a list of lists.
If you want to do it by hand, you can still use other list functions (which might be good exercise in itself):
let manualSplitInto count list =
let l = List.length list
let n = l / count
let r = l % count
List.append
[(List.take (n+r) list)]
(List.unfold (fun rest ->
match rest with
| [] -> None
| _ -> let taken = min n (List.length rest)
Some (List.take taken rest, List.skip taken rest))
(List.skip (n+r) list))
Here, List.unfold does the iteration (recursing) part for you.
So, if you really want to train working with recursive functions, you will end up writing your own List.unfold replacement or something more tailored to your concrete use case.
let pedestrianSplitInto count list =
let l = List.length list
let n = l / count
let r = l % count
let rec step rest acc =
match rest with
| [] -> acc
| _ ->
let taken = min n (List.length rest)
step (List.skip taken rest) ((List.take taken rest) :: acc)
List.rev (step (List.skip (n+r) list) [List.take (n+r) list])
Please observe how similar the implementation of function step is to the lambda given to List.unfold in manualSplitInto.
If you also do not want to use functions like List.take or List.skip, you will have to go even lower level and do element wise operations, such as:
let rec splitAtIndex index front rear =
match index with
| 0 -> (List.rev front, rear)
| _ -> splitAtIndex (index - 1) ((List.head rear) :: front) (List.tail rear)
let stillLivingOnTreesSplitInto count list =
let l = List.length list
let n = l / count
let r = l % count
let rec collect result (front,rear) =
match rear with
| [] -> (front :: result)
| _ -> collect (front :: result) (splitAtIndex n [] rear)
let x = splitAtIndex (n+r) [] list
collect [] x |> List.rev
If you know it will always be triplets then this should work.
let xs = [1..7]
let n = List.length xs
let y = List.mapi (fun i x -> (x, 3 * i / n)) xs
List.foldBack (fun (x, i) (a,b,c) -> match i with 0 -> (x::a,b,c) | 1 -> (a,x::b,c) | 2 -> (a,b,x::c)) y (([],[],[]))

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

Adding no value to return list

I'm having a problem with understanding how F# works. I come from C# and I think that I'm trying to make F# work like C#. My biggest problem is returning values in the correct format.
Example:
Let's say I have function that takes a list of integers and an integer.
Function should print a list of indexes where values from list match passed integer.
My code:
let indeks myList n = myList |> List.mapi (fun i x -> if x=n then i else 0);;
indeks [0..4] 3;;
However it returns:
val it : int list = [0; 0; 0; 3; 0]
instead of just [3] as I cannot ommit else in that statement.
Also I have targeted signature of -> int list -> int -> int list and I get something else.
Same goes for problem no. 2 where I want to provide an integer and print every number from 0 to this integer n times (where n is the iterated value):
example:
MultiplyValues 3;;
output: [1;2;2;3;3;3]
Best I could do was to create list of lists.
What am I missing when returning elements?
How do I add nothing to the return
example: if x=n then n else AddNothingToTheReturn
Use List.choose:
let indeks lst n =
lst
|> List.mapi (fun i s -> if s = n then Some i else None)
|> List.choose id
Sorry, I didn't notice that you had a second problem too. For that you can use List.collect:
let f (n : int) : list<int> =
[1 .. n]
|> List.collect (fun s -> List.init s (fun t -> s))
printfn "%A" (f 3) // [1; 2; 2; 3; 3; 3]
Please read the documentation for List.collect for more information.
EDIT
Following s952163's lead, here is another version of the first solution without the Option type:
let indeks (lst : list<int>) (n : int) : list<int> =
lst
|> List.fold (fun (s, t) u -> s + 1, (if u = n then (s :: t) else t)) (0, [])
|> (snd >> List.rev)
This one traverses the original list once, and the (potentially much shorter) newly formed list once.
The previous answer is quite idiomatic. Here's one solution that avoids the use of Option types and id:
let indeks2 lst n =
lst
|> List.mapi (fun i x -> (i,x))
|> List.filter (fun x -> (fst x) % n = 0 )
|> List.map snd
You can modify the filter function to match your needs.
If you plan to generate lots of sequences it might be a good idea to explore Sequence (list) comprehensions:
[for i in 1..10 do
yield! List.replicate i i]
If statements are an expression in F# and they return a value. In this case both the IF and ELSE branch must return the same type of value. Using Some/None (Option type) gets around this. There are some cases where you can get away with just using If.

How do I increment a certain index of a list?

here's my code: (should work fine)
let rec interleave = function
| ([],ys) -> []
| (xs,[]) -> []
| (x::xs,y::ys) -> x :: y :: interleave (xs, ys)
let gencut n list =
let first = list |> Seq.take n |> Seq.toList
let last = list |> Seq.skip n |> Seq.toList
(first, last)
let cut list = gencut ((List.length list)/2) list
let shuffle x = interleave (cut x)
let isNotSame (list1, list2) = if list1 = list2 then false else true
let countShuffles xs =
let mutable newList = xs
let mutable x = 1
if (List.length(xs) > 1) then newList <- shuffle newList
while isNotSame (newList, xs) do
newList <- shuffle newList
x <- x + 1
x
//lists countShuffles from 1 to x
let listShuffles x =
for i = 1 to x/2 do
let y = [1..(i*2)]
let z = countShuffles y
printf "A deck of %d cards takes %d shuffles\n" (i*2) z
printf ""
The flow is (from main function down to 1st helper):
listShuffles -> countShuffles -> shuffle + isNotSame -> cut -> gencut + interleave
(so just try listShuffles)
What "countShuffles" does is:
take an int, creates a list, (1..n), (which is supposed to represent a deck of cards),
cuts it in half, does a perfect-out shuffle (perfect bridge shuffle)
and counts how many shuffles it takes to make the deck original again
What listShuffles does is:
takes an int, and prints out countShuffles 1 through n
(you need an even amount of cards in the deck)
Sorry about the explanation, now my question:
is it possible to see how many times a certain number is returned?
i.e.:
listShuffles 10000;;
see how many times "16" appeared.
i was thinking of making a list.
and incrementing a given index.
which represents a certain number that was returned.
but i cant find how to do that...
p.s. i dont care how my code is wrong or anything like that,
this is my first F# program, and it is homework based on my professor's criteria,
(the assignment is complete, this question is for curiosity)
There are a few alternatives
If you only want one number you can do
List |> Seq.sumBy (fun t -> if t = 16 then 1 else 0)
If you want a range of different numbers, it may be better to do
let map = List |> Seq.countBy (fun t -> t) |> Map.ofSeq
then map.[16] is the number of times that 16 occurs in the list
You can do something like:
let listShuffles x =
[| for i = 1 to x/2 do
yield countShuffles [1..(i*2)] |]
Now this function return array and then you can use Array module functions to find how many times a number appears
listShuffles 1000 |> Array.filter ((=) 16) |> Array.length
Or to print all such numbers and their occurrence count:
listShuffles 100
|> Array.toSeq |> Seq.groupBy id
|> Seq.iter (fun (k,v) -> printfn "%d appears %d times" k (v.Count()))